blob: a2237d4b2cf29c71742b6a81638b2ce43f792d51 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware
3 monitoring
Jean Delvare5f49ef82005-09-22 21:50:47 +02004 Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
6 Mark D. Studebaker <mdsxyz123@yahoo.com>
Jean Delvaref1183012005-09-22 21:58:41 +02007 Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008
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
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24/*
Jean Delvareaaf7f142005-09-22 22:09:07 +020025 Supports the following VIA south bridges:
26
27 Chip name PCI ID REV I2C block
28 VT82C596A 0x3050 no
29 VT82C596B 0x3051 no
30 VT82C686A 0x3057 0x30 no
31 VT82C686B 0x3057 0x40 yes
32 VT8231 0x8235 no?
33 VT8233 0x3074 yes
34 VT8233A 0x3147 yes?
35 VT8235 0x3177 yes
36 VT8237R 0x3227 yes
37
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 Note: we assume there can only be one device, with one SMBus interface.
39*/
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/module.h>
42#include <linux/delay.h>
43#include <linux/pci.h>
44#include <linux/kernel.h>
45#include <linux/stddef.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070046#include <linux/ioport.h>
47#include <linux/i2c.h>
48#include <linux/init.h>
49#include <asm/io.h>
50
51static struct pci_dev *vt596_pdev;
52
Jean Delvare5f49ef82005-09-22 21:50:47 +020053#define SMBBA1 0x90
54#define SMBBA2 0x80
55#define SMBBA3 0xD0
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57/* SMBus address offsets */
58static unsigned short vt596_smba;
59#define SMBHSTSTS (vt596_smba + 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define SMBHSTCNT (vt596_smba + 2)
61#define SMBHSTCMD (vt596_smba + 3)
62#define SMBHSTADD (vt596_smba + 4)
63#define SMBHSTDAT0 (vt596_smba + 5)
64#define SMBHSTDAT1 (vt596_smba + 6)
65#define SMBBLKDAT (vt596_smba + 7)
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67/* PCI Address Constants */
68
69/* SMBus data in configuration space can be found in two places,
Jean Delvare5f49ef82005-09-22 21:50:47 +020070 We try to select the better one */
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Jean Delvarec2f559d2005-09-22 22:01:07 +020072static unsigned short SMBHSTCFG = 0xD2;
Linus Torvalds1da177e2005-04-16 15:20:36 -070073
74/* Other settings */
75#define MAX_TIMEOUT 500
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
77/* VT82C596 constants */
Jean Delvare5f49ef82005-09-22 21:50:47 +020078#define VT596_QUICK 0x00
79#define VT596_BYTE 0x04
80#define VT596_BYTE_DATA 0x08
81#define VT596_WORD_DATA 0x0C
82#define VT596_BLOCK_DATA 0x14
Jean Delvaref1183012005-09-22 21:58:41 +020083#define VT596_I2C_BLOCK_DATA 0x34
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
85
86/* If force is set to anything different from 0, we forcibly enable the
87 VT596. DANGEROUS! */
88static int force;
89module_param(force, bool, 0);
90MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
91
92/* If force_addr is set to anything different from 0, we forcibly enable
93 the VT596 at the given address. VERY DANGEROUS! */
94static u16 force_addr;
95module_param(force_addr, ushort, 0);
96MODULE_PARM_DESC(force_addr,
97 "Forcibly enable the SMBus at the given address. "
98 "EXTREMELY DANGEROUS!");
99
100
Jean Delvarec2f559d2005-09-22 22:01:07 +0200101static struct pci_driver vt596_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static struct i2c_adapter vt596_adapter;
103
Jean Delvaref1183012005-09-22 21:58:41 +0200104#define FEATURE_I2CBLOCK (1<<0)
105static unsigned int vt596_features;
106
Jean Delvareed5453e2005-09-22 22:23:32 +0200107#ifdef DEBUG
108static void vt596_dump_regs(const char *msg, u8 size)
109{
110 dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x "
111 "DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
112 inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
113 inb_p(SMBHSTDAT1));
114
115 if (size == VT596_BLOCK_DATA
116 || size == VT596_I2C_BLOCK_DATA) {
117 int i;
118
119 dev_dbg(&vt596_adapter.dev, "BLK=");
120 for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++)
121 printk("%02x,", inb_p(SMBBLKDAT));
122 printk("\n");
123 dev_dbg(&vt596_adapter.dev, " ");
124 for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++)
125 printk("%02x,", inb_p(SMBBLKDAT));
126 printk("%02x\n", inb_p(SMBBLKDAT));
127 }
128}
Greg KHca68f112005-09-22 22:23:32 +0200129#else
130static inline void vt596_dump_regs(const char *msg, u8 size) { }
Jean Delvareed5453e2005-09-22 22:23:32 +0200131#endif
132
Jean Delvarec2f559d2005-09-22 22:01:07 +0200133/* Return -1 on error, 0 on success */
Jean Delvare50c1cc32005-09-22 22:15:53 +0200134static int vt596_transaction(u8 size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
136 int temp;
137 int result = 0;
138 int timeout = 0;
139
Jean Delvareed5453e2005-09-22 22:23:32 +0200140 vt596_dump_regs("Transaction (pre)", size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142 /* Make sure the SMBus host is ready to start transmitting */
143 if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
144 dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
Jean Delvare87501972005-10-31 18:51:21 +0100145 "Resetting...\n", temp);
Jean Delvare5f49ef82005-09-22 21:50:47 +0200146
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 outb_p(temp, SMBHSTSTS);
148 if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
Jean Delvare87501972005-10-31 18:51:21 +0100149 dev_err(&vt596_adapter.dev, "SMBus reset failed! "
150 "(0x%02x)\n", temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
153 }
154
Jean Delvarec2f559d2005-09-22 22:01:07 +0200155 /* Start the transaction by setting bit 6 */
Jean Delvare87501972005-10-31 18:51:21 +0100156 outb_p(0x40 | size, SMBHSTCNT);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Jean Delvarec2f559d2005-09-22 22:01:07 +0200158 /* We will always wait for a fraction of a second */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 do {
160 msleep(1);
161 temp = inb_p(SMBHSTSTS);
162 } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
163
164 /* If the SMBus is still busy, we give up */
165 if (timeout >= MAX_TIMEOUT) {
166 result = -1;
Jean Delvarec2f559d2005-09-22 22:01:07 +0200167 dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
169
170 if (temp & 0x10) {
171 result = -1;
Jean Delvarec2f559d2005-09-22 22:01:07 +0200172 dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
Jean Delvare87501972005-10-31 18:51:21 +0100173 size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 }
175
176 if (temp & 0x08) {
177 result = -1;
Jean Delvarec2f559d2005-09-22 22:01:07 +0200178 dev_err(&vt596_adapter.dev, "SMBus collision!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 }
180
181 if (temp & 0x04) {
Jean Delvare87501972005-10-31 18:51:21 +0100182 int read = inb_p(SMBHSTADD) & 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 result = -1;
Jean Delvare87501972005-10-31 18:51:21 +0100184 /* The quick and receive byte commands are used to probe
185 for chips, so errors are expected, and we don't want
186 to frighten the user. */
187 if (!((size == VT596_QUICK && !read) ||
188 (size == VT596_BYTE && read)))
Jean Delvarec2f559d2005-09-22 22:01:07 +0200189 dev_err(&vt596_adapter.dev, "Transaction error!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 }
191
Jean Delvarec2f559d2005-09-22 22:01:07 +0200192 /* Resetting status register */
193 if (temp & 0x1F)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 outb_p(temp, SMBHSTSTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
Jean Delvareed5453e2005-09-22 22:23:32 +0200196 vt596_dump_regs("Transaction (post)", size);
Jean Delvare5f49ef82005-09-22 21:50:47 +0200197
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198 return result;
199}
200
Jean Delvarec2f559d2005-09-22 22:01:07 +0200201/* Return -1 on error, 0 on success */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
Jean Delvare5f49ef82005-09-22 21:50:47 +0200203 unsigned short flags, char read_write, u8 command,
204 int size, union i2c_smbus_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
Jean Delvarec2f559d2005-09-22 22:01:07 +0200206 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 switch (size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 case I2C_SMBUS_QUICK:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 size = VT596_QUICK;
211 break;
212 case I2C_SMBUS_BYTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 if (read_write == I2C_SMBUS_WRITE)
214 outb_p(command, SMBHSTCMD);
215 size = VT596_BYTE;
216 break;
217 case I2C_SMBUS_BYTE_DATA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 outb_p(command, SMBHSTCMD);
219 if (read_write == I2C_SMBUS_WRITE)
220 outb_p(data->byte, SMBHSTDAT0);
221 size = VT596_BYTE_DATA;
222 break;
223 case I2C_SMBUS_WORD_DATA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 outb_p(command, SMBHSTCMD);
225 if (read_write == I2C_SMBUS_WRITE) {
226 outb_p(data->word & 0xff, SMBHSTDAT0);
227 outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
228 }
229 size = VT596_WORD_DATA;
230 break;
Jean Delvaref1183012005-09-22 21:58:41 +0200231 case I2C_SMBUS_I2C_BLOCK_DATA:
232 if (!(vt596_features & FEATURE_I2CBLOCK))
Jean Delvarec2f559d2005-09-22 22:01:07 +0200233 goto exit_unsupported;
Jean Delvaref1183012005-09-22 21:58:41 +0200234 if (read_write == I2C_SMBUS_READ)
235 outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0);
236 /* Fall through */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 case I2C_SMBUS_BLOCK_DATA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 outb_p(command, SMBHSTCMD);
239 if (read_write == I2C_SMBUS_WRITE) {
Jean Delvarec2f559d2005-09-22 22:01:07 +0200240 u8 len = data->block[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 if (len > I2C_SMBUS_BLOCK_MAX)
242 len = I2C_SMBUS_BLOCK_MAX;
243 outb_p(len, SMBHSTDAT0);
Jean Delvarec2f559d2005-09-22 22:01:07 +0200244 inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 for (i = 1; i <= len; i++)
246 outb_p(data->block[i], SMBBLKDAT);
247 }
Jean Delvaref1183012005-09-22 21:58:41 +0200248 size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ?
249 VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 break;
Jean Delvarec2f559d2005-09-22 22:01:07 +0200251 default:
252 goto exit_unsupported;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 }
254
Jean Delvarec2f559d2005-09-22 22:01:07 +0200255 outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256
Jean Delvare50c1cc32005-09-22 22:15:53 +0200257 if (vt596_transaction(size)) /* Error in transaction */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 return -1;
259
260 if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
261 return 0;
262
263 switch (size) {
264 case VT596_BYTE:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 case VT596_BYTE_DATA:
266 data->byte = inb_p(SMBHSTDAT0);
267 break;
268 case VT596_WORD_DATA:
269 data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
270 break;
Jean Delvaref1183012005-09-22 21:58:41 +0200271 case VT596_I2C_BLOCK_DATA:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 case VT596_BLOCK_DATA:
273 data->block[0] = inb_p(SMBHSTDAT0);
274 if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
275 data->block[0] = I2C_SMBUS_BLOCK_MAX;
Jean Delvarec2f559d2005-09-22 22:01:07 +0200276 inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 for (i = 1; i <= data->block[0]; i++)
278 data->block[i] = inb_p(SMBBLKDAT);
279 break;
280 }
281 return 0;
Jean Delvarec2f559d2005-09-22 22:01:07 +0200282
283exit_unsupported:
284 dev_warn(&vt596_adapter.dev, "Unsupported command invoked! (0x%02x)\n",
285 size);
286 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287}
288
289static u32 vt596_func(struct i2c_adapter *adapter)
290{
Jean Delvaref1183012005-09-22 21:58:41 +0200291 u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
293 I2C_FUNC_SMBUS_BLOCK_DATA;
Jean Delvaref1183012005-09-22 21:58:41 +0200294
295 if (vt596_features & FEATURE_I2CBLOCK)
296 func |= I2C_FUNC_SMBUS_I2C_BLOCK;
297 return func;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299
300static struct i2c_algorithm smbus_algorithm = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 .smbus_xfer = vt596_access,
302 .functionality = vt596_func,
303};
304
305static struct i2c_adapter vt596_adapter = {
306 .owner = THIS_MODULE,
307 .class = I2C_CLASS_HWMON,
308 .algo = &smbus_algorithm,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309};
310
311static int __devinit vt596_probe(struct pci_dev *pdev,
312 const struct pci_device_id *id)
313{
314 unsigned char temp;
315 int error = -ENODEV;
Jean Delvare5f49ef82005-09-22 21:50:47 +0200316
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 /* Determine the address of the SMBus areas */
318 if (force_addr) {
319 vt596_smba = force_addr & 0xfff0;
320 force = 0;
321 goto found;
322 }
323
324 if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) ||
Jean Delvarec2f559d2005-09-22 22:01:07 +0200325 !(vt596_smba & 0x0001)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 /* try 2nd address and config reg. for 596 */
327 if (id->device == PCI_DEVICE_ID_VIA_82C596_3 &&
328 !pci_read_config_word(pdev, SMBBA2, &vt596_smba) &&
Jean Delvarec2f559d2005-09-22 22:01:07 +0200329 (vt596_smba & 0x0001)) {
330 SMBHSTCFG = 0x84;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 } else {
332 /* no matches at all */
333 dev_err(&pdev->dev, "Cannot configure "
334 "SMBus I/O Base address\n");
335 return -ENODEV;
336 }
337 }
338
339 vt596_smba &= 0xfff0;
340 if (vt596_smba == 0) {
341 dev_err(&pdev->dev, "SMBus base address "
342 "uninitialized - upgrade BIOS or use "
343 "force_addr=0xaddr\n");
344 return -ENODEV;
345 }
346
Jean Delvare5f49ef82005-09-22 21:50:47 +0200347found:
Jean Delvarec2f559d2005-09-22 22:01:07 +0200348 if (!request_region(vt596_smba, 8, vt596_driver.name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
Jean Delvare5f49ef82005-09-22 21:50:47 +0200350 vt596_smba);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 return -ENODEV;
352 }
353
354 pci_read_config_byte(pdev, SMBHSTCFG, &temp);
355 /* If force_addr is set, we program the new address here. Just to make
356 sure, we disable the VT596 first. */
357 if (force_addr) {
358 pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe);
359 pci_write_config_word(pdev, id->driver_data, vt596_smba);
360 pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
361 dev_warn(&pdev->dev, "WARNING: SMBus interface set to new "
Jean Delvare5f49ef82005-09-22 21:50:47 +0200362 "address 0x%04x!\n", vt596_smba);
Jean Delvarec2f559d2005-09-22 22:01:07 +0200363 } else if (!(temp & 0x01)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 if (force) {
Jean Delvare5f49ef82005-09-22 21:50:47 +0200365 /* NOTE: This assumes I/O space and other allocations
366 * WERE done by the Bios! Don't complain if your
367 * hardware does weird things after enabling this.
368 * :') Check for Bios updates before resorting to
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 * this.
370 */
Jean Delvarec2f559d2005-09-22 22:01:07 +0200371 pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 dev_info(&pdev->dev, "Enabling SMBus device\n");
373 } else {
374 dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
375 "controller not enabled! - upgrade BIOS or "
376 "use force=1\n");
377 goto release_region;
378 }
379 }
380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
382
Jean Delvaref1183012005-09-22 21:58:41 +0200383 switch (pdev->device) {
384 case PCI_DEVICE_ID_VIA_8237:
385 case PCI_DEVICE_ID_VIA_8235:
386 case PCI_DEVICE_ID_VIA_8233A:
387 case PCI_DEVICE_ID_VIA_8233_0:
388 vt596_features |= FEATURE_I2CBLOCK;
389 break;
390 case PCI_DEVICE_ID_VIA_82C686_4:
391 /* The VT82C686B (rev 0x40) does support I2C block
392 transactions, but the VT82C686A (rev 0x30) doesn't */
393 if (!pci_read_config_byte(pdev, PCI_REVISION_ID, &temp)
394 && temp >= 0x40)
395 vt596_features |= FEATURE_I2CBLOCK;
396 break;
397 }
398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 vt596_adapter.dev.parent = &pdev->dev;
400 snprintf(vt596_adapter.name, I2C_NAME_SIZE,
Jean Delvare5f49ef82005-09-22 21:50:47 +0200401 "SMBus Via Pro adapter at %04x", vt596_smba);
402
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 vt596_pdev = pci_dev_get(pdev);
404 if (i2c_add_adapter(&vt596_adapter)) {
405 pci_dev_put(vt596_pdev);
406 vt596_pdev = NULL;
407 }
408
409 /* Always return failure here. This is to allow other drivers to bind
410 * to this pci device. We don't really want to have control over the
411 * pci device, we only wanted to read as few register values from it.
412 */
413 return -ENODEV;
414
Jean Delvare5f49ef82005-09-22 21:50:47 +0200415release_region:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 release_region(vt596_smba, 8);
417 return error;
418}
419
420static struct pci_device_id vt596_ids[] = {
421 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
422 .driver_data = SMBBA1 },
423 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
424 .driver_data = SMBBA1 },
425 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4),
426 .driver_data = SMBBA1 },
427 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0),
428 .driver_data = SMBBA3 },
429 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A),
430 .driver_data = SMBBA3 },
431 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235),
432 .driver_data = SMBBA3 },
433 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
434 .driver_data = SMBBA3 },
435 { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
436 .driver_data = SMBBA1 },
437 { 0, }
438};
439
Jean Delvare5f49ef82005-09-22 21:50:47 +0200440MODULE_DEVICE_TABLE(pci, vt596_ids);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442static struct pci_driver vt596_driver = {
Laurent Riffardccd7aa02005-10-17 22:47:48 +0200443 .owner = THIS_MODULE,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 .name = "vt596_smbus",
445 .id_table = vt596_ids,
446 .probe = vt596_probe,
447};
448
449static int __init i2c_vt596_init(void)
450{
451 return pci_register_driver(&vt596_driver);
452}
453
454
455static void __exit i2c_vt596_exit(void)
456{
457 pci_unregister_driver(&vt596_driver);
458 if (vt596_pdev != NULL) {
459 i2c_del_adapter(&vt596_adapter);
460 release_region(vt596_smba, 8);
461 pci_dev_put(vt596_pdev);
462 vt596_pdev = NULL;
463 }
464}
465
Jean Delvare87501972005-10-31 18:51:21 +0100466MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
467 "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
468 "Jean Delvare <khali@linux-fr.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469MODULE_DESCRIPTION("vt82c596 SMBus driver");
470MODULE_LICENSE("GPL");
471
472module_init(i2c_vt596_init);
473module_exit(i2c_vt596_exit);