xref: /openbmc/linux/drivers/i2c/busses/i2c-viapro.c (revision 4b4193256c8d3bc3a5397b5cd9494c2ad386317d)
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