1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
496de0e25SJan Engelhardt Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
51da177e4SLinus Torvalds Mark D. Studebaker <mdsxyz123@yahoo.com>
67c81c60fSJean Delvare Copyright (C) 2005 - 2008 Jean Delvare <jdelvare@suse.de>
71da177e4SLinus Torvalds
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds /*
11aaf7f147SJean Delvare Supports the following VIA south bridges:
12aaf7f147SJean Delvare
13aaf7f147SJean Delvare Chip name PCI ID REV I2C block
14aaf7f147SJean Delvare VT82C596A 0x3050 no
15aaf7f147SJean Delvare VT82C596B 0x3051 no
16aaf7f147SJean Delvare VT82C686A 0x3057 0x30 no
17aaf7f147SJean Delvare VT82C686B 0x3057 0x40 yes
18aaf7f147SJean Delvare VT8231 0x8235 no?
19aaf7f147SJean Delvare VT8233 0x3074 yes
20aaf7f147SJean Delvare VT8233A 0x3147 yes?
21aaf7f147SJean Delvare VT8235 0x3177 yes
22aaf7f147SJean Delvare VT8237R 0x3227 yes
23c243353aSRudolf Marek VT8237A 0x3337 yes
240d227a7eSJean Delvare VT8237S 0x3372 yes
25c243353aSRudolf Marek VT8251 0x3287 yes
26ab6a6ed2SJean Delvare CX700 0x8324 yes
27b806a71aSRudolf Marek VX800/VX820 0x8353 yes
28a231591fSHarald Welte VX855/VX875 0x8409 yes
29aaf7f147SJean Delvare
301da177e4SLinus Torvalds Note: we assume there can only be one device, with one SMBus interface.
311da177e4SLinus Torvalds */
321da177e4SLinus Torvalds
331da177e4SLinus Torvalds #include <linux/module.h>
341da177e4SLinus Torvalds #include <linux/delay.h>
351da177e4SLinus Torvalds #include <linux/pci.h>
361da177e4SLinus Torvalds #include <linux/kernel.h>
371da177e4SLinus Torvalds #include <linux/stddef.h>
381da177e4SLinus Torvalds #include <linux/ioport.h>
391da177e4SLinus Torvalds #include <linux/i2c.h>
401da177e4SLinus Torvalds #include <linux/init.h>
4154fb4a05SJean Delvare #include <linux/acpi.h>
4221782180SH Hartley Sweeten #include <linux/io.h>
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds static struct pci_dev *vt596_pdev;
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds #define SMBBA1 0x90
471da177e4SLinus Torvalds #define SMBBA2 0x80
481da177e4SLinus Torvalds #define SMBBA3 0xD0
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds /* SMBus address offsets */
511da177e4SLinus Torvalds static unsigned short vt596_smba;
521da177e4SLinus Torvalds #define SMBHSTSTS (vt596_smba + 0)
531da177e4SLinus Torvalds #define SMBHSTCNT (vt596_smba + 2)
541da177e4SLinus Torvalds #define SMBHSTCMD (vt596_smba + 3)
551da177e4SLinus Torvalds #define SMBHSTADD (vt596_smba + 4)
561da177e4SLinus Torvalds #define SMBHSTDAT0 (vt596_smba + 5)
571da177e4SLinus Torvalds #define SMBHSTDAT1 (vt596_smba + 6)
581da177e4SLinus Torvalds #define SMBBLKDAT (vt596_smba + 7)
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds /* PCI Address Constants */
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds /* SMBus data in configuration space can be found in two places,
631da177e4SLinus Torvalds We try to select the better one */
641da177e4SLinus Torvalds
65c2f559d5SJean Delvare static unsigned short SMBHSTCFG = 0xD2;
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds /* Other settings */
681da177e4SLinus Torvalds #define MAX_TIMEOUT 500
691da177e4SLinus Torvalds
701da177e4SLinus Torvalds /* VT82C596 constants */
711da177e4SLinus Torvalds #define VT596_QUICK 0x00
721da177e4SLinus Torvalds #define VT596_BYTE 0x04
731da177e4SLinus Torvalds #define VT596_BYTE_DATA 0x08
741da177e4SLinus Torvalds #define VT596_WORD_DATA 0x0C
75a05f2c5aSPrakash Mortha #define VT596_PROC_CALL 0x10
761da177e4SLinus Torvalds #define VT596_BLOCK_DATA 0x14
77f1183014SJean Delvare #define VT596_I2C_BLOCK_DATA 0x34
781da177e4SLinus Torvalds
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds /* If force is set to anything different from 0, we forcibly enable the
811da177e4SLinus Torvalds VT596. DANGEROUS! */
8290ab5ee9SRusty Russell static bool force;
831da177e4SLinus Torvalds module_param(force, bool, 0);
841da177e4SLinus Torvalds MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds /* If force_addr is set to anything different from 0, we forcibly enable
871da177e4SLinus Torvalds the VT596 at the given address. VERY DANGEROUS! */
881da177e4SLinus Torvalds static u16 force_addr;
89c78babccSDavid Howells module_param_hw(force_addr, ushort, ioport, 0);
901da177e4SLinus Torvalds MODULE_PARM_DESC(force_addr,
911da177e4SLinus Torvalds "Forcibly enable the SMBus at the given address. "
921da177e4SLinus Torvalds "EXTREMELY DANGEROUS!");
931da177e4SLinus Torvalds
941da177e4SLinus Torvalds
95c2f559d5SJean Delvare static struct pci_driver vt596_driver;
961da177e4SLinus Torvalds static struct i2c_adapter vt596_adapter;
971da177e4SLinus Torvalds
98f1183014SJean Delvare #define FEATURE_I2CBLOCK (1<<0)
99f1183014SJean Delvare static unsigned int vt596_features;
100f1183014SJean Delvare
101ed5453e5SJean Delvare #ifdef DEBUG
vt596_dump_regs(const char * msg,u8 size)102ed5453e5SJean Delvare static void vt596_dump_regs(const char *msg, u8 size)
103ed5453e5SJean Delvare {
104ed5453e5SJean Delvare dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x "
105ed5453e5SJean Delvare "DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
106ed5453e5SJean Delvare inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
107ed5453e5SJean Delvare inb_p(SMBHSTDAT1));
108ed5453e5SJean Delvare
109ed5453e5SJean Delvare if (size == VT596_BLOCK_DATA
110ed5453e5SJean Delvare || size == VT596_I2C_BLOCK_DATA) {
111ed5453e5SJean Delvare int i;
112ed5453e5SJean Delvare
113ed5453e5SJean Delvare dev_dbg(&vt596_adapter.dev, "BLK=");
114ed5453e5SJean Delvare for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++)
115ed5453e5SJean Delvare printk("%02x,", inb_p(SMBBLKDAT));
116ed5453e5SJean Delvare printk("\n");
117ed5453e5SJean Delvare dev_dbg(&vt596_adapter.dev, " ");
118ed5453e5SJean Delvare for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++)
119ed5453e5SJean Delvare printk("%02x,", inb_p(SMBBLKDAT));
120ed5453e5SJean Delvare printk("%02x\n", inb_p(SMBBLKDAT));
121ed5453e5SJean Delvare }
122ed5453e5SJean Delvare }
123ca68f119SGreg KH #else
vt596_dump_regs(const char * msg,u8 size)124ca68f119SGreg KH static inline void vt596_dump_regs(const char *msg, u8 size) { }
125ed5453e5SJean Delvare #endif
126ed5453e5SJean Delvare
127c2f559d5SJean Delvare /* Return -1 on error, 0 on success */
vt596_transaction(u8 size)12850c1cc33SJean Delvare static int vt596_transaction(u8 size)
1291da177e4SLinus Torvalds {
1301da177e4SLinus Torvalds int temp;
1311da177e4SLinus Torvalds int result = 0;
1321da177e4SLinus Torvalds int timeout = 0;
1331da177e4SLinus Torvalds
134ed5453e5SJean Delvare vt596_dump_regs("Transaction (pre)", size);
1351da177e4SLinus Torvalds
1361da177e4SLinus Torvalds /* Make sure the SMBus host is ready to start transmitting */
1371da177e4SLinus Torvalds if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
1381da177e4SLinus Torvalds dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
1398750197fSJean Delvare "Resetting...\n", temp);
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds outb_p(temp, SMBHSTSTS);
1421da177e4SLinus Torvalds if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
1438750197fSJean Delvare dev_err(&vt596_adapter.dev, "SMBus reset failed! "
1448750197fSJean Delvare "(0x%02x)\n", temp);
14597140342SDavid Brownell return -EBUSY;
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds }
1481da177e4SLinus Torvalds
149c2f559d5SJean Delvare /* Start the transaction by setting bit 6 */
1508750197fSJean Delvare outb_p(0x40 | size, SMBHSTCNT);
1511da177e4SLinus Torvalds
152c2f559d5SJean Delvare /* We will always wait for a fraction of a second */
1531da177e4SLinus Torvalds do {
1541da177e4SLinus Torvalds msleep(1);
1551da177e4SLinus Torvalds temp = inb_p(SMBHSTSTS);
156b6a31950SRoel Kluin } while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds /* If the SMBus is still busy, we give up */
159b6a31950SRoel Kluin if (timeout == MAX_TIMEOUT) {
16097140342SDavid Brownell result = -ETIMEDOUT;
161c2f559d5SJean Delvare dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds
1641da177e4SLinus Torvalds if (temp & 0x10) {
16597140342SDavid Brownell result = -EIO;
166c2f559d5SJean Delvare dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
1678750197fSJean Delvare size);
1681da177e4SLinus Torvalds }
1691da177e4SLinus Torvalds
1701da177e4SLinus Torvalds if (temp & 0x08) {
17197140342SDavid Brownell result = -EIO;
172c2f559d5SJean Delvare dev_err(&vt596_adapter.dev, "SMBus collision!\n");
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds
1751da177e4SLinus Torvalds if (temp & 0x04) {
17697140342SDavid Brownell result = -ENXIO;
177bf5d95c8SJean Delvare dev_dbg(&vt596_adapter.dev, "No response\n");
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds
180c2f559d5SJean Delvare /* Resetting status register */
181c2f559d5SJean Delvare if (temp & 0x1F)
1821da177e4SLinus Torvalds outb_p(temp, SMBHSTSTS);
1831da177e4SLinus Torvalds
184ed5453e5SJean Delvare vt596_dump_regs("Transaction (post)", size);
1851da177e4SLinus Torvalds
1861da177e4SLinus Torvalds return result;
1871da177e4SLinus Torvalds }
1881da177e4SLinus Torvalds
18997140342SDavid Brownell /* Return negative errno on error, 0 on success */
vt596_access(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)1901da177e4SLinus Torvalds static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
1911da177e4SLinus Torvalds unsigned short flags, char read_write, u8 command,
1921da177e4SLinus Torvalds int size, union i2c_smbus_data *data)
1931da177e4SLinus Torvalds {
194c2f559d5SJean Delvare int i;
19597140342SDavid Brownell int status;
1961da177e4SLinus Torvalds
1971da177e4SLinus Torvalds switch (size) {
1981da177e4SLinus Torvalds case I2C_SMBUS_QUICK:
1991da177e4SLinus Torvalds size = VT596_QUICK;
2001da177e4SLinus Torvalds break;
2011da177e4SLinus Torvalds case I2C_SMBUS_BYTE:
2021da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE)
2031da177e4SLinus Torvalds outb_p(command, SMBHSTCMD);
2041da177e4SLinus Torvalds size = VT596_BYTE;
2051da177e4SLinus Torvalds break;
2061da177e4SLinus Torvalds case I2C_SMBUS_BYTE_DATA:
2071da177e4SLinus Torvalds outb_p(command, SMBHSTCMD);
2081da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE)
2091da177e4SLinus Torvalds outb_p(data->byte, SMBHSTDAT0);
2101da177e4SLinus Torvalds size = VT596_BYTE_DATA;
2111da177e4SLinus Torvalds break;
2121da177e4SLinus Torvalds case I2C_SMBUS_WORD_DATA:
2131da177e4SLinus Torvalds outb_p(command, SMBHSTCMD);
2141da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) {
2151da177e4SLinus Torvalds outb_p(data->word & 0xff, SMBHSTDAT0);
2161da177e4SLinus Torvalds outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
2171da177e4SLinus Torvalds }
2181da177e4SLinus Torvalds size = VT596_WORD_DATA;
2191da177e4SLinus Torvalds break;
220a05f2c5aSPrakash Mortha case I2C_SMBUS_PROC_CALL:
221a05f2c5aSPrakash Mortha outb_p(command, SMBHSTCMD);
222a05f2c5aSPrakash Mortha outb_p(data->word & 0xff, SMBHSTDAT0);
223a05f2c5aSPrakash Mortha outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
224a05f2c5aSPrakash Mortha size = VT596_PROC_CALL;
225a05f2c5aSPrakash Mortha break;
226f1183014SJean Delvare case I2C_SMBUS_I2C_BLOCK_DATA:
227f1183014SJean Delvare if (!(vt596_features & FEATURE_I2CBLOCK))
228c2f559d5SJean Delvare goto exit_unsupported;
229f1183014SJean Delvare if (read_write == I2C_SMBUS_READ)
2304b2643d7SJean Delvare outb_p(data->block[0], SMBHSTDAT0);
231*4db7e178SGustavo A. R. Silva fallthrough;
2321da177e4SLinus Torvalds case I2C_SMBUS_BLOCK_DATA:
2331da177e4SLinus Torvalds outb_p(command, SMBHSTCMD);
2341da177e4SLinus Torvalds if (read_write == I2C_SMBUS_WRITE) {
235c2f559d5SJean Delvare u8 len = data->block[0];
2361da177e4SLinus Torvalds if (len > I2C_SMBUS_BLOCK_MAX)
2371da177e4SLinus Torvalds len = I2C_SMBUS_BLOCK_MAX;
2381da177e4SLinus Torvalds outb_p(len, SMBHSTDAT0);
239c2f559d5SJean Delvare inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
2401da177e4SLinus Torvalds for (i = 1; i <= len; i++)
2411da177e4SLinus Torvalds outb_p(data->block[i], SMBBLKDAT);
2421da177e4SLinus Torvalds }
243f1183014SJean Delvare size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ?
244f1183014SJean Delvare VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA;
2451da177e4SLinus Torvalds break;
246c2f559d5SJean Delvare default:
247c2f559d5SJean Delvare goto exit_unsupported;
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds
250c2f559d5SJean Delvare outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD);
2511da177e4SLinus Torvalds
25297140342SDavid Brownell status = vt596_transaction(size);
25397140342SDavid Brownell if (status)
25497140342SDavid Brownell return status;
2551da177e4SLinus Torvalds
256a05f2c5aSPrakash Mortha if (size == VT596_PROC_CALL)
257a05f2c5aSPrakash Mortha read_write = I2C_SMBUS_READ;
258a05f2c5aSPrakash Mortha
2591da177e4SLinus Torvalds if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
2601da177e4SLinus Torvalds return 0;
2611da177e4SLinus Torvalds
2621da177e4SLinus Torvalds switch (size) {
2631da177e4SLinus Torvalds case VT596_BYTE:
2641da177e4SLinus Torvalds case VT596_BYTE_DATA:
2651da177e4SLinus Torvalds data->byte = inb_p(SMBHSTDAT0);
2661da177e4SLinus Torvalds break;
2671da177e4SLinus Torvalds case VT596_WORD_DATA:
268a05f2c5aSPrakash Mortha case VT596_PROC_CALL:
2691da177e4SLinus Torvalds data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
2701da177e4SLinus Torvalds break;
271f1183014SJean Delvare case VT596_I2C_BLOCK_DATA:
2721da177e4SLinus Torvalds case VT596_BLOCK_DATA:
2731da177e4SLinus Torvalds data->block[0] = inb_p(SMBHSTDAT0);
2741da177e4SLinus Torvalds if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
2751da177e4SLinus Torvalds data->block[0] = I2C_SMBUS_BLOCK_MAX;
276c2f559d5SJean Delvare inb_p(SMBHSTCNT); /* Reset SMBBLKDAT */
2771da177e4SLinus Torvalds for (i = 1; i <= data->block[0]; i++)
2781da177e4SLinus Torvalds data->block[i] = inb_p(SMBBLKDAT);
2791da177e4SLinus Torvalds break;
2801da177e4SLinus Torvalds }
2811da177e4SLinus Torvalds return 0;
282c2f559d5SJean Delvare
283c2f559d5SJean Delvare exit_unsupported:
284ac7fc4fbSJean Delvare dev_warn(&vt596_adapter.dev, "Unsupported transaction %d\n",
285c2f559d5SJean Delvare size);
28697140342SDavid Brownell return -EOPNOTSUPP;
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds
vt596_func(struct i2c_adapter * adapter)2891da177e4SLinus Torvalds static u32 vt596_func(struct i2c_adapter *adapter)
2901da177e4SLinus Torvalds {
291f1183014SJean Delvare u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
2921da177e4SLinus Torvalds I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
293a05f2c5aSPrakash Mortha I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
294f1183014SJean Delvare
295f1183014SJean Delvare if (vt596_features & FEATURE_I2CBLOCK)
296f1183014SJean Delvare func |= I2C_FUNC_SMBUS_I2C_BLOCK;
297f1183014SJean Delvare return func;
2981da177e4SLinus Torvalds }
2991da177e4SLinus Torvalds
3008f9082c5SJean Delvare static const struct i2c_algorithm smbus_algorithm = {
3011da177e4SLinus Torvalds .smbus_xfer = vt596_access,
3021da177e4SLinus Torvalds .functionality = vt596_func,
3031da177e4SLinus Torvalds };
3041da177e4SLinus Torvalds
3051da177e4SLinus Torvalds static struct i2c_adapter vt596_adapter = {
3061da177e4SLinus Torvalds .owner = THIS_MODULE,
3073401b2ffSJean Delvare .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
3081da177e4SLinus Torvalds .algo = &smbus_algorithm,
3091da177e4SLinus Torvalds };
3101da177e4SLinus Torvalds
vt596_probe(struct pci_dev * pdev,const struct pci_device_id * id)3110b255e92SBill Pemberton static int vt596_probe(struct pci_dev *pdev,
3121da177e4SLinus Torvalds const struct pci_device_id *id)
3131da177e4SLinus Torvalds {
3141da177e4SLinus Torvalds unsigned char temp;
3157c1f59c9SJean Delvare int error;
3161da177e4SLinus Torvalds
3171da177e4SLinus Torvalds /* Determine the address of the SMBus areas */
3181da177e4SLinus Torvalds if (force_addr) {
3191da177e4SLinus Torvalds vt596_smba = force_addr & 0xfff0;
3201da177e4SLinus Torvalds force = 0;
3211da177e4SLinus Torvalds goto found;
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds
3241da177e4SLinus Torvalds if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) ||
325c2f559d5SJean Delvare !(vt596_smba & 0x0001)) {
3261da177e4SLinus Torvalds /* try 2nd address and config reg. for 596 */
3271da177e4SLinus Torvalds if (id->device == PCI_DEVICE_ID_VIA_82C596_3 &&
3281da177e4SLinus Torvalds !pci_read_config_word(pdev, SMBBA2, &vt596_smba) &&
329c2f559d5SJean Delvare (vt596_smba & 0x0001)) {
330c2f559d5SJean Delvare SMBHSTCFG = 0x84;
3311da177e4SLinus Torvalds } else {
3321da177e4SLinus Torvalds /* no matches at all */
3331da177e4SLinus Torvalds dev_err(&pdev->dev, "Cannot configure "
3341da177e4SLinus Torvalds "SMBus I/O Base address\n");
3351da177e4SLinus Torvalds return -ENODEV;
3361da177e4SLinus Torvalds }
3371da177e4SLinus Torvalds }
3381da177e4SLinus Torvalds
3391da177e4SLinus Torvalds vt596_smba &= 0xfff0;
3401da177e4SLinus Torvalds if (vt596_smba == 0) {
3411da177e4SLinus Torvalds dev_err(&pdev->dev, "SMBus base address "
3421da177e4SLinus Torvalds "uninitialized - upgrade BIOS or use "
3431da177e4SLinus Torvalds "force_addr=0xaddr\n");
3441da177e4SLinus Torvalds return -ENODEV;
3451da177e4SLinus Torvalds }
3461da177e4SLinus Torvalds
3471da177e4SLinus Torvalds found:
34854fb4a05SJean Delvare error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
34954fb4a05SJean Delvare if (error)
35018669eabSJean Delvare return -ENODEV;
35154fb4a05SJean Delvare
352c2f559d5SJean Delvare if (!request_region(vt596_smba, 8, vt596_driver.name)) {
3531da177e4SLinus Torvalds dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
3541da177e4SLinus Torvalds vt596_smba);
3551da177e4SLinus Torvalds return -ENODEV;
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds
3581da177e4SLinus Torvalds pci_read_config_byte(pdev, SMBHSTCFG, &temp);
3591da177e4SLinus Torvalds /* If force_addr is set, we program the new address here. Just to make
3601da177e4SLinus Torvalds sure, we disable the VT596 first. */
3611da177e4SLinus Torvalds if (force_addr) {
3621da177e4SLinus Torvalds pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe);
3631da177e4SLinus Torvalds pci_write_config_word(pdev, id->driver_data, vt596_smba);
3641da177e4SLinus Torvalds pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
3651da177e4SLinus Torvalds dev_warn(&pdev->dev, "WARNING: SMBus interface set to new "
3661da177e4SLinus Torvalds "address 0x%04x!\n", vt596_smba);
367c2f559d5SJean Delvare } else if (!(temp & 0x01)) {
3681da177e4SLinus Torvalds if (force) {
3691da177e4SLinus Torvalds /* NOTE: This assumes I/O space and other allocations
3701da177e4SLinus Torvalds * WERE done by the Bios! Don't complain if your
3711da177e4SLinus Torvalds * hardware does weird things after enabling this.
3721da177e4SLinus Torvalds * :') Check for Bios updates before resorting to
3731da177e4SLinus Torvalds * this.
3741da177e4SLinus Torvalds */
375c2f559d5SJean Delvare pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
3761da177e4SLinus Torvalds dev_info(&pdev->dev, "Enabling SMBus device\n");
3771da177e4SLinus Torvalds } else {
3781da177e4SLinus Torvalds dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
3791da177e4SLinus Torvalds "controller not enabled! - upgrade BIOS or "
3801da177e4SLinus Torvalds "use force=1\n");
3817c1f59c9SJean Delvare error = -ENODEV;
3821da177e4SLinus Torvalds goto release_region;
3831da177e4SLinus Torvalds }
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds
3861da177e4SLinus Torvalds dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
3871da177e4SLinus Torvalds
388f1183014SJean Delvare switch (pdev->device) {
389ab6a6ed2SJean Delvare case PCI_DEVICE_ID_VIA_CX700:
390b806a71aSRudolf Marek case PCI_DEVICE_ID_VIA_VX800:
391a231591fSHarald Welte case PCI_DEVICE_ID_VIA_VX855:
39201d56a6aSJean Delvare case PCI_DEVICE_ID_VIA_VX900:
393c243353aSRudolf Marek case PCI_DEVICE_ID_VIA_8251:
394f1183014SJean Delvare case PCI_DEVICE_ID_VIA_8237:
395c243353aSRudolf Marek case PCI_DEVICE_ID_VIA_8237A:
3960d227a7eSJean Delvare case PCI_DEVICE_ID_VIA_8237S:
397f1183014SJean Delvare case PCI_DEVICE_ID_VIA_8235:
398f1183014SJean Delvare case PCI_DEVICE_ID_VIA_8233A:
399f1183014SJean Delvare case PCI_DEVICE_ID_VIA_8233_0:
400f1183014SJean Delvare vt596_features |= FEATURE_I2CBLOCK;
401f1183014SJean Delvare break;
402f1183014SJean Delvare case PCI_DEVICE_ID_VIA_82C686_4:
403f1183014SJean Delvare /* The VT82C686B (rev 0x40) does support I2C block
404f1183014SJean Delvare transactions, but the VT82C686A (rev 0x30) doesn't */
40544c10138SAuke Kok if (pdev->revision >= 0x40)
406f1183014SJean Delvare vt596_features |= FEATURE_I2CBLOCK;
407f1183014SJean Delvare break;
408f1183014SJean Delvare }
409f1183014SJean Delvare
4101da177e4SLinus Torvalds vt596_adapter.dev.parent = &pdev->dev;
4112096b956SDavid Brownell snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
4121da177e4SLinus Torvalds "SMBus Via Pro adapter at %04x", vt596_smba);
4131da177e4SLinus Torvalds
4141da177e4SLinus Torvalds vt596_pdev = pci_dev_get(pdev);
4157c1f59c9SJean Delvare error = i2c_add_adapter(&vt596_adapter);
4167c1f59c9SJean Delvare if (error) {
4171da177e4SLinus Torvalds pci_dev_put(vt596_pdev);
4181da177e4SLinus Torvalds vt596_pdev = NULL;
4197c1f59c9SJean Delvare goto release_region;
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds
4221da177e4SLinus Torvalds /* Always return failure here. This is to allow other drivers to bind
4231da177e4SLinus Torvalds * to this pci device. We don't really want to have control over the
4241da177e4SLinus Torvalds * pci device, we only wanted to read as few register values from it.
4251da177e4SLinus Torvalds */
4261da177e4SLinus Torvalds return -ENODEV;
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds release_region:
4291da177e4SLinus Torvalds release_region(vt596_smba, 8);
4301da177e4SLinus Torvalds return error;
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds
433392debf1SJingoo Han static const struct pci_device_id vt596_ids[] = {
4341da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
4351da177e4SLinus Torvalds .driver_data = SMBBA1 },
4361da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
4371da177e4SLinus Torvalds .driver_data = SMBBA1 },
4381da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4),
4391da177e4SLinus Torvalds .driver_data = SMBBA1 },
4401da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0),
4411da177e4SLinus Torvalds .driver_data = SMBBA3 },
4421da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A),
4431da177e4SLinus Torvalds .driver_data = SMBBA3 },
4441da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235),
4451da177e4SLinus Torvalds .driver_data = SMBBA3 },
4461da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
4471da177e4SLinus Torvalds .driver_data = SMBBA3 },
448c243353aSRudolf Marek { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
449c243353aSRudolf Marek .driver_data = SMBBA3 },
4500d227a7eSJean Delvare { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
4510d227a7eSJean Delvare .driver_data = SMBBA3 },
4521da177e4SLinus Torvalds { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
4531da177e4SLinus Torvalds .driver_data = SMBBA1 },
454c243353aSRudolf Marek { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
455c243353aSRudolf Marek .driver_data = SMBBA3 },
456ab6a6ed2SJean Delvare { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
457ab6a6ed2SJean Delvare .driver_data = SMBBA3 },
458b806a71aSRudolf Marek { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
459b806a71aSRudolf Marek .driver_data = SMBBA3 },
460a231591fSHarald Welte { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855),
461a231591fSHarald Welte .driver_data = SMBBA3 },
46201d56a6aSJean Delvare { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX900),
46301d56a6aSJean Delvare .driver_data = SMBBA3 },
4641da177e4SLinus Torvalds { 0, }
4651da177e4SLinus Torvalds };
4661da177e4SLinus Torvalds
4671da177e4SLinus Torvalds MODULE_DEVICE_TABLE(pci, vt596_ids);
4681da177e4SLinus Torvalds
4691da177e4SLinus Torvalds static struct pci_driver vt596_driver = {
4701da177e4SLinus Torvalds .name = "vt596_smbus",
4711da177e4SLinus Torvalds .id_table = vt596_ids,
4721da177e4SLinus Torvalds .probe = vt596_probe,
4731da177e4SLinus Torvalds };
4741da177e4SLinus Torvalds
i2c_vt596_init(void)4751da177e4SLinus Torvalds static int __init i2c_vt596_init(void)
4761da177e4SLinus Torvalds {
4771da177e4SLinus Torvalds return pci_register_driver(&vt596_driver);
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds
4801da177e4SLinus Torvalds
i2c_vt596_exit(void)4811da177e4SLinus Torvalds static void __exit i2c_vt596_exit(void)
4821da177e4SLinus Torvalds {
4831da177e4SLinus Torvalds pci_unregister_driver(&vt596_driver);
4841da177e4SLinus Torvalds if (vt596_pdev != NULL) {
4851da177e4SLinus Torvalds i2c_del_adapter(&vt596_adapter);
4861da177e4SLinus Torvalds release_region(vt596_smba, 8);
4871da177e4SLinus Torvalds pci_dev_put(vt596_pdev);
4881da177e4SLinus Torvalds vt596_pdev = NULL;
4891da177e4SLinus Torvalds }
4901da177e4SLinus Torvalds }
4911da177e4SLinus Torvalds
492f80531c8SJarkko Nikula MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>");
493f80531c8SJarkko Nikula MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");
494f80531c8SJarkko Nikula MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
4951da177e4SLinus Torvalds MODULE_DESCRIPTION("vt82c596 SMBus driver");
4961da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4971da177e4SLinus Torvalds
4981da177e4SLinus Torvalds module_init(i2c_vt596_init);
4991da177e4SLinus Torvalds module_exit(i2c_vt596_exit);
500