11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
25f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare    Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
396de0e252cedffad61b3cb5e05662c591898e69aJan Engelhardt    Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Mark D. Studebaker <mdsxyz123@yahoo.com>
50d227a7e724460bddcd603a1feb672267bcb0d6cJean Delvare    Copyright (C) 2005 - 2008  Jean Delvare <khali@linux-fr.org>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    the Free Software Foundation; either version 2 of the License, or
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    (at your option) any later version.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    This program is distributed in the hope that it will be useful,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    GNU General Public License for more details.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    You should have received a copy of the GNU General Public License
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    along with this program; if not, write to the Free Software
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
23aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   Supports the following VIA south bridges:
24aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare
25aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   Chip name          PCI ID  REV     I2C block
26aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT82C596A          0x3050             no
27aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT82C596B          0x3051             no
28aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT82C686A          0x3057  0x30       no
29aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT82C686B          0x3057  0x40       yes
30aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT8231             0x8235             no?
31aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT8233             0x3074             yes
32aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT8233A            0x3147             yes?
33aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT8235             0x3177             yes
34aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare   VT8237R            0x3227             yes
35c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek   VT8237A            0x3337             yes
360d227a7e724460bddcd603a1feb672267bcb0d6cJean Delvare   VT8237S            0x3372             yes
37c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek   VT8251             0x3287             yes
38ab6a6ed271c757b429ddc68f5b93a41f9592ab8bJean Delvare   CX700              0x8324             yes
39b806a71a0e9dacb6763371561caa693c78b93d40Rudolf Marek   VX800/VX820        0x8353             yes
40a231591f0427cfb91ae247be974a7fa0e6b37389Harald Welte   VX855/VX875        0x8409             yes
41aaf7f1477668f34dda65aba17e87c0bc2ebe84d1Jean Delvare
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   Note: we assume there can only be one device, with one SMBus interface.
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/stddef.h>
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h>
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
5354fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare#include <linux/acpi.h>
542178218027e4da0608219fae1d02e5c88f4e560dH Hartley Sweeten#include <linux/io.h>
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_dev *vt596_pdev;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
585f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define SMBBA1		0x90
595f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define SMBBA2		0x80
605f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define SMBBA3		0xD0
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SMBus address offsets */
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned short vt596_smba;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTSTS	(vt596_smba + 0)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCNT	(vt596_smba + 2)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTCMD	(vt596_smba + 3)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTADD	(vt596_smba + 4)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTDAT0	(vt596_smba + 5)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBHSTDAT1	(vt596_smba + 6)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SMBBLKDAT	(vt596_smba + 7)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* PCI Address Constants */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* SMBus data in configuration space can be found in two places,
755f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare   We try to select the better one */
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
77c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvarestatic unsigned short SMBHSTCFG = 0xD2;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Other settings */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_TIMEOUT	500
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* VT82C596 constants */
835f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define VT596_QUICK		0x00
845f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define VT596_BYTE		0x04
855f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define VT596_BYTE_DATA		0x08
865f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define VT596_WORD_DATA		0x0C
87a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha#define VT596_PROC_CALL		0x10
885f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare#define VT596_BLOCK_DATA	0x14
89f118301416953d677de738100c33eb8cfb7adecbJean Delvare#define VT596_I2C_BLOCK_DATA	0x34
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If force is set to anything different from 0, we forcibly enable the
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   VT596. DANGEROUS! */
9490ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool force;
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force, bool, 0);
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* If force_addr is set to anything different from 0, we forcibly enable
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   the VT596 at the given address. VERY DANGEROUS! */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 force_addr;
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "Forcibly enable the SMBus at the given address. "
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 "EXTREMELY DANGEROUS!");
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
107c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvarestatic struct pci_driver vt596_driver;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_adapter vt596_adapter;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
110f118301416953d677de738100c33eb8cfb7adecbJean Delvare#define FEATURE_I2CBLOCK	(1<<0)
111f118301416953d677de738100c33eb8cfb7adecbJean Delvarestatic unsigned int vt596_features;
112f118301416953d677de738100c33eb8cfb7adecbJean Delvare
113ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare#ifdef DEBUG
114ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvarestatic void vt596_dump_regs(const char *msg, u8 size)
115ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare{
116ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare	dev_dbg(&vt596_adapter.dev, "%s: STS=%02x CNT=%02x CMD=%02x ADD=%02x "
117ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		"DAT=%02x,%02x\n", msg, inb_p(SMBHSTSTS), inb_p(SMBHSTCNT),
118ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		inb_p(SMBHSTCMD), inb_p(SMBHSTADD), inb_p(SMBHSTDAT0),
119ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		inb_p(SMBHSTDAT1));
120ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare
121ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare	if (size == VT596_BLOCK_DATA
122ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare	 || size == VT596_I2C_BLOCK_DATA) {
123ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		int i;
124ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare
125ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		dev_dbg(&vt596_adapter.dev, "BLK=");
126ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		for (i = 0; i < I2C_SMBUS_BLOCK_MAX / 2; i++)
127ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare			printk("%02x,", inb_p(SMBBLKDAT));
128ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		printk("\n");
129ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		dev_dbg(&vt596_adapter.dev, "    ");
130ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		for (; i < I2C_SMBUS_BLOCK_MAX - 1; i++)
131ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare			printk("%02x,", inb_p(SMBBLKDAT));
132ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare		printk("%02x\n", inb_p(SMBBLKDAT));
133ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare	}
134ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare}
135ca68f1193e8fc86470d4222d563d13b5584dc4f8Greg Kroah-Hartman#else
136ca68f1193e8fc86470d4222d563d13b5584dc4f8Greg Kroah-Hartmanstatic inline void vt596_dump_regs(const char *msg, u8 size) { }
137ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare#endif
138ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare
139c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare/* Return -1 on error, 0 on success */
14050c1cc339ca72f7cb95d440d384346f4238dc494Jean Delvarestatic int vt596_transaction(u8 size)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int temp;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int result = 0;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int timeout = 0;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
146ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare	vt596_dump_regs("Transaction (pre)", size);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Make sure the SMBus host is ready to start transmitting */
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_dbg(&vt596_adapter.dev, "SMBus busy (0x%02x). "
1518750197f0e8f5467297d72e11444cf32f29d790fJean Delvare			"Resetting...\n", temp);
1525f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(temp, SMBHSTSTS);
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((temp = inb_p(SMBHSTSTS)) & 0x1F) {
1558750197f0e8f5467297d72e11444cf32f29d790fJean Delvare			dev_err(&vt596_adapter.dev, "SMBus reset failed! "
1568750197f0e8f5467297d72e11444cf32f29d790fJean Delvare				"(0x%02x)\n", temp);
15797140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell			return -EBUSY;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
161c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	/* Start the transaction by setting bit 6 */
1628750197f0e8f5467297d72e11444cf32f29d790fJean Delvare	outb_p(0x40 | size, SMBHSTCNT);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
164c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	/* We will always wait for a fraction of a second */
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		msleep(1);
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		temp = inb_p(SMBHSTSTS);
168b6a3195070fe1c12d0bb1099ffe997d8abf9f602Roel Kluin	} while ((temp & 0x01) && (++timeout < MAX_TIMEOUT));
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If the SMBus is still busy, we give up */
171b6a3195070fe1c12d0bb1099ffe997d8abf9f602Roel Kluin	if (timeout == MAX_TIMEOUT) {
17297140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -ETIMEDOUT;
173c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare		dev_err(&vt596_adapter.dev, "SMBus timeout!\n");
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & 0x10) {
17797140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -EIO;
178c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare		dev_err(&vt596_adapter.dev, "Transaction failed (0x%02x)\n",
1798750197f0e8f5467297d72e11444cf32f29d790fJean Delvare			size);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & 0x08) {
18397140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -EIO;
184c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare		dev_err(&vt596_adapter.dev, "SMBus collision!\n");
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (temp & 0x04) {
18897140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		result = -ENXIO;
189bf5d95c82692ead9ba7876af73dac2edcc8a6191Jean Delvare		dev_dbg(&vt596_adapter.dev, "No response\n");
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
192c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	/* Resetting status register */
193c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	if (temp & 0x1F)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(temp, SMBHSTSTS);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
196ed5453e54f0c4a29605fd8399f58649d8739f5f0Jean Delvare	vt596_dump_regs("Transaction (post)", size);
1975f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return result;
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
20197140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell/* Return negative errno on error, 0 on success */
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic s32 vt596_access(struct i2c_adapter *adap, u16 addr,
2035f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare		unsigned short flags, char read_write, u8 command,
2045f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare		int size, union i2c_smbus_data *data)
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
206c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	int i;
20797140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell	int status;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (size) {
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_QUICK:
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = VT596_QUICK;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_BYTE:
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE)
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(command, SMBHSTCMD);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = VT596_BYTE;
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_BYTE_DATA:
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(command, SMBHSTCMD);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE)
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(data->byte, SMBHSTDAT0);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = VT596_BYTE_DATA;
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_WORD_DATA:
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(command, SMBHSTCMD);
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE) {
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(data->word & 0xff, SMBHSTDAT0);
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = VT596_WORD_DATA;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
232a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha	case I2C_SMBUS_PROC_CALL:
233a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha		outb_p(command, SMBHSTCMD);
234a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha		outb_p(data->word & 0xff, SMBHSTDAT0);
235a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha		outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
236a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha		size = VT596_PROC_CALL;
237a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha		break;
238f118301416953d677de738100c33eb8cfb7adecbJean Delvare	case I2C_SMBUS_I2C_BLOCK_DATA:
239f118301416953d677de738100c33eb8cfb7adecbJean Delvare		if (!(vt596_features & FEATURE_I2CBLOCK))
240c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare			goto exit_unsupported;
241f118301416953d677de738100c33eb8cfb7adecbJean Delvare		if (read_write == I2C_SMBUS_READ)
2424b2643d7d9bdcd776749e17f73c168ddf02e93cbJean Delvare			outb_p(data->block[0], SMBHSTDAT0);
243f118301416953d677de738100c33eb8cfb7adecbJean Delvare		/* Fall through */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case I2C_SMBUS_BLOCK_DATA:
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		outb_p(command, SMBHSTCMD);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (read_write == I2C_SMBUS_WRITE) {
247c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare			u8 len = data->block[0];
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (len > I2C_SMBUS_BLOCK_MAX)
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				len = I2C_SMBUS_BLOCK_MAX;
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			outb_p(len, SMBHSTDAT0);
251c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare			inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			for (i = 1; i <= len; i++)
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				outb_p(data->block[i], SMBBLKDAT);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
255f118301416953d677de738100c33eb8cfb7adecbJean Delvare		size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ?
256f118301416953d677de738100c33eb8cfb7adecbJean Delvare		       VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA;
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
258c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	default:
259c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare		goto exit_unsupported;
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
262c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	outb_p(((addr & 0x7f) << 1) | read_write, SMBHSTADD);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
26497140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell	status = vt596_transaction(size);
26597140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell	if (status)
26697140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell		return status;
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
268a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha	if (size == VT596_PROC_CALL)
269a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha		read_write = I2C_SMBUS_READ;
270a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (size) {
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT596_BYTE:
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT596_BYTE_DATA:
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->byte = inb_p(SMBHSTDAT0);
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT596_WORD_DATA:
280a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha	case VT596_PROC_CALL:
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
283f118301416953d677de738100c33eb8cfb7adecbJean Delvare	case VT596_I2C_BLOCK_DATA:
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case VT596_BLOCK_DATA:
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		data->block[0] = inb_p(SMBHSTDAT0);
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->block[0] = I2C_SMBUS_BLOCK_MAX;
288c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare		inb_p(SMBHSTCNT);	/* Reset SMBBLKDAT */
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for (i = 1; i <= data->block[0]; i++)
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			data->block[i] = inb_p(SMBBLKDAT);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
294c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare
295c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvareexit_unsupported:
296ac7fc4fb2b6a126af8d07f46500440c9641976cfJean Delvare	dev_warn(&vt596_adapter.dev, "Unsupported transaction %d\n",
297c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare		 size);
29897140342e69d479a3ad82bfd4c154c0b08fe3eeaDavid Brownell	return -EOPNOTSUPP;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u32 vt596_func(struct i2c_adapter *adapter)
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
303f118301416953d677de738100c33eb8cfb7adecbJean Delvare	u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
305a05f2c5a2735ee1d68770137fbbfc334d3b9cda9Prakash Mortha	    I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
306f118301416953d677de738100c33eb8cfb7adecbJean Delvare
307f118301416953d677de738100c33eb8cfb7adecbJean Delvare	if (vt596_features & FEATURE_I2CBLOCK)
308f118301416953d677de738100c33eb8cfb7adecbJean Delvare		func |= I2C_FUNC_SMBUS_I2C_BLOCK;
309f118301416953d677de738100c33eb8cfb7adecbJean Delvare	return func;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3128f9082c5ce0e2c2f7ad0211b0c089f680d2efc11Jean Delvarestatic const struct i2c_algorithm smbus_algorithm = {
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.smbus_xfer	= vt596_access,
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.functionality	= vt596_func,
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_adapter vt596_adapter = {
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.owner		= THIS_MODULE,
3193401b2fff38fbb8b73ea6bcc69a8370ae5d2a7a0Jean Delvare	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD,
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.algo		= &smbus_algorithm,
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit vt596_probe(struct pci_dev *pdev,
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 const struct pci_device_id *id)
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char temp;
3277c1f59c9d5caf3a84f35549b5d58f3c055a68da5Jean Delvare	int error;
3285f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Determine the address of the SMBus areas */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (force_addr) {
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vt596_smba = force_addr & 0xfff0;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		force = 0;
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto found;
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((pci_read_config_word(pdev, id->driver_data, &vt596_smba)) ||
337c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	    !(vt596_smba & 0x0001)) {
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* try 2nd address and config reg. for 596 */
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (id->device == PCI_DEVICE_ID_VIA_82C596_3 &&
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		    !pci_read_config_word(pdev, SMBBA2, &vt596_smba) &&
341c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare		    (vt596_smba & 0x0001)) {
342c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare			SMBHSTCFG = 0x84;
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* no matches at all */
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&pdev->dev, "Cannot configure "
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"SMBus I/O Base address\n");
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -ENODEV;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vt596_smba &= 0xfff0;
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vt596_smba == 0) {
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&pdev->dev, "SMBus base address "
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"uninitialized - upgrade BIOS or use "
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"force_addr=0xaddr\n");
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3595f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvarefound:
36054fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare	error = acpi_check_region(vt596_smba, 8, vt596_driver.name);
36154fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare	if (error)
36218669eabde2ff5fc446e72e043f0539059763438Jean Delvare		return -ENODEV;
36354fb4a05af0a4b814e6716cfdf3fa97fc6be7a32Jean Delvare
364c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	if (!request_region(vt596_smba, 8, vt596_driver.name)) {
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n",
3665f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare			vt596_smba);
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENODEV;
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(pdev, SMBHSTCFG, &temp);
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* If force_addr is set, we program the new address here. Just to make
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   sure, we disable the VT596 first. */
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (force_addr) {
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_byte(pdev, SMBHSTCFG, temp & 0xfe);
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_word(pdev, id->driver_data, vt596_smba);
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev_warn(&pdev->dev, "WARNING: SMBus interface set to new "
3785f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare			 "address 0x%04x!\n", vt596_smba);
379c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare	} else if (!(temp & 0x01)) {
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (force) {
3815f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare			/* NOTE: This assumes I/O space and other allocations
3825f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare			 * WERE done by the Bios!  Don't complain if your
3835f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare			 * hardware does weird things after enabling this.
3845f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare			 * :') Check for Bios updates before resorting to
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 * this.
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			 */
387c2f559d5df5751780c0bd3ea0bd0aa17d47c0b39Jean Delvare			pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_info(&pdev->dev, "Enabling SMBus device\n");
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev_err(&pdev->dev, "SMBUS: Error: Host SMBus "
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"controller not enabled! - upgrade BIOS or "
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"use force=1\n");
3937c1f59c9d5caf3a84f35549b5d58f3c055a68da5Jean Delvare			error = -ENODEV;
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto release_region;
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
400f118301416953d677de738100c33eb8cfb7adecbJean Delvare	switch (pdev->device) {
401ab6a6ed271c757b429ddc68f5b93a41f9592ab8bJean Delvare	case PCI_DEVICE_ID_VIA_CX700:
402b806a71a0e9dacb6763371561caa693c78b93d40Rudolf Marek	case PCI_DEVICE_ID_VIA_VX800:
403a231591f0427cfb91ae247be974a7fa0e6b37389Harald Welte	case PCI_DEVICE_ID_VIA_VX855:
404c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek	case PCI_DEVICE_ID_VIA_8251:
405f118301416953d677de738100c33eb8cfb7adecbJean Delvare	case PCI_DEVICE_ID_VIA_8237:
406c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek	case PCI_DEVICE_ID_VIA_8237A:
4070d227a7e724460bddcd603a1feb672267bcb0d6cJean Delvare	case PCI_DEVICE_ID_VIA_8237S:
408f118301416953d677de738100c33eb8cfb7adecbJean Delvare	case PCI_DEVICE_ID_VIA_8235:
409f118301416953d677de738100c33eb8cfb7adecbJean Delvare	case PCI_DEVICE_ID_VIA_8233A:
410f118301416953d677de738100c33eb8cfb7adecbJean Delvare	case PCI_DEVICE_ID_VIA_8233_0:
411f118301416953d677de738100c33eb8cfb7adecbJean Delvare		vt596_features |= FEATURE_I2CBLOCK;
412f118301416953d677de738100c33eb8cfb7adecbJean Delvare		break;
413f118301416953d677de738100c33eb8cfb7adecbJean Delvare	case PCI_DEVICE_ID_VIA_82C686_4:
414f118301416953d677de738100c33eb8cfb7adecbJean Delvare		/* The VT82C686B (rev 0x40) does support I2C block
415f118301416953d677de738100c33eb8cfb7adecbJean Delvare		   transactions, but the VT82C686A (rev 0x30) doesn't */
41644c10138fd4bbc4b6d6bff0873c24902f2a9da65Auke Kok		if (pdev->revision >= 0x40)
417f118301416953d677de738100c33eb8cfb7adecbJean Delvare			vt596_features |= FEATURE_I2CBLOCK;
418f118301416953d677de738100c33eb8cfb7adecbJean Delvare		break;
419f118301416953d677de738100c33eb8cfb7adecbJean Delvare	}
420f118301416953d677de738100c33eb8cfb7adecbJean Delvare
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vt596_adapter.dev.parent = &pdev->dev;
4222096b956d24c4b5950b808fc23b218425d79ebb1David Brownell	snprintf(vt596_adapter.name, sizeof(vt596_adapter.name),
4235f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare		 "SMBus Via Pro adapter at %04x", vt596_smba);
4245f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvare
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	vt596_pdev = pci_dev_get(pdev);
4267c1f59c9d5caf3a84f35549b5d58f3c055a68da5Jean Delvare	error = i2c_add_adapter(&vt596_adapter);
4277c1f59c9d5caf3a84f35549b5d58f3c055a68da5Jean Delvare	if (error) {
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_dev_put(vt596_pdev);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vt596_pdev = NULL;
4307c1f59c9d5caf3a84f35549b5d58f3c055a68da5Jean Delvare		goto release_region;
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Always return failure here.  This is to allow other drivers to bind
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * to this pci device.  We don't really want to have control over the
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * pci device, we only wanted to read as few register values from it.
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -ENODEV;
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4395f49ef8e8cefe0a95948b4270db28507c1c287d4Jean Delvarerelease_region:
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(vt596_smba, 8);
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return error;
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4443527bd5045aacb4e4072f9cacb8eb9a433fbad39Axel Linstatic DEFINE_PCI_DEVICE_TABLE(vt596_ids) = {
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA1 },
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA1 },
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4),
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA1 },
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_0),
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA3 },
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233A),
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA3 },
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235),
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA3 },
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA3 },
459c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
460c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek	  .driver_data = SMBBA3 },
4610d227a7e724460bddcd603a1feb672267bcb0d6cJean Delvare	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237S),
4620d227a7e724460bddcd603a1feb672267bcb0d6cJean Delvare	  .driver_data = SMBBA3 },
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	  .driver_data = SMBBA1 },
465c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
466c243353a90fae3a9a85d2bd79b1df06bb21c568aRudolf Marek	  .driver_data = SMBBA3 },
467ab6a6ed271c757b429ddc68f5b93a41f9592ab8bJean Delvare	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
468ab6a6ed271c757b429ddc68f5b93a41f9592ab8bJean Delvare	  .driver_data = SMBBA3 },
469b806a71a0e9dacb6763371561caa693c78b93d40Rudolf Marek	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
470b806a71a0e9dacb6763371561caa693c78b93d40Rudolf Marek	  .driver_data = SMBBA3 },
471a231591f0427cfb91ae247be974a7fa0e6b37389Harald Welte	{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855),
472a231591f0427cfb91ae247be974a7fa0e6b37389Harald Welte	  .driver_data = SMBBA3 },
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ 0, }
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4765f49ef8e8cefe0a95948b4270db28507c1c287d4Jean DelvareMODULE_DEVICE_TABLE(pci, vt596_ids);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver vt596_driver = {
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name		= "vt596_smbus",
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table	= vt596_ids,
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe		= vt596_probe,
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init i2c_vt596_init(void)
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return pci_register_driver(&vt596_driver);
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit i2c_vt596_exit(void)
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&vt596_driver);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (vt596_pdev != NULL) {
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		i2c_del_adapter(&vt596_adapter);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_region(vt596_smba, 8);
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pci_dev_put(vt596_pdev);
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		vt596_pdev = NULL;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5018750197f0e8f5467297d72e11444cf32f29d790fJean DelvareMODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
5028750197f0e8f5467297d72e11444cf32f29d790fJean Delvare	      "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
5038750197f0e8f5467297d72e11444cf32f29d790fJean Delvare	      "Jean Delvare <khali@linux-fr.org>");
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("vt82c596 SMBus driver");
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(i2c_vt596_init);
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(i2c_vt596_exit);
509