xref: /OK3568_Linux_fs/kernel/drivers/i2c/busses/i2c-sis5595.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun     Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
4*4882a593Smuzhiyun     Philip Edelbrock <phil@netroedge.com>
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun /* Note: we assume there can only be one SIS5595 with one SMBus interface */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun /*
11*4882a593Smuzhiyun    Note: all have mfr. ID 0x1039.
12*4882a593Smuzhiyun    SUPPORTED		PCI ID
13*4882a593Smuzhiyun 	5595		0008
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun    Note: these chips contain a 0008 device which is incompatible with the
16*4882a593Smuzhiyun          5595. We recognize these by the presence of the listed
17*4882a593Smuzhiyun          "blacklist" PCI ID and refuse to load.
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun    NOT SUPPORTED	PCI ID		BLACKLIST PCI ID
20*4882a593Smuzhiyun 	 540		0008		0540
21*4882a593Smuzhiyun 	 550		0008		0550
22*4882a593Smuzhiyun 	5513		0008		5511
23*4882a593Smuzhiyun 	5581		0008		5597
24*4882a593Smuzhiyun 	5582		0008		5597
25*4882a593Smuzhiyun 	5597		0008		5597
26*4882a593Smuzhiyun 	5598		0008		5597/5598
27*4882a593Smuzhiyun 	 630		0008		0630
28*4882a593Smuzhiyun 	 645		0008		0645
29*4882a593Smuzhiyun 	 646		0008		0646
30*4882a593Smuzhiyun 	 648		0008		0648
31*4882a593Smuzhiyun 	 650		0008		0650
32*4882a593Smuzhiyun 	 651		0008		0651
33*4882a593Smuzhiyun 	 730		0008		0730
34*4882a593Smuzhiyun 	 735		0008		0735
35*4882a593Smuzhiyun 	 745		0008		0745
36*4882a593Smuzhiyun 	 746		0008		0746
37*4882a593Smuzhiyun */
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun /* TO DO:
40*4882a593Smuzhiyun  * Add Block Transfers (ugly, but supported by the adapter)
41*4882a593Smuzhiyun  * Add adapter resets
42*4882a593Smuzhiyun  */
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun #include <linux/kernel.h>
45*4882a593Smuzhiyun #include <linux/module.h>
46*4882a593Smuzhiyun #include <linux/delay.h>
47*4882a593Smuzhiyun #include <linux/pci.h>
48*4882a593Smuzhiyun #include <linux/ioport.h>
49*4882a593Smuzhiyun #include <linux/init.h>
50*4882a593Smuzhiyun #include <linux/i2c.h>
51*4882a593Smuzhiyun #include <linux/acpi.h>
52*4882a593Smuzhiyun #include <linux/io.h>
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun static int blacklist[] = {
55*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_540,
56*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_550,
57*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_630,
58*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_645,
59*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_646,
60*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_648,
61*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_650,
62*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_651,
63*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_730,
64*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_735,
65*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_745,
66*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_746,
67*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_5511,	/* 5513 chip has the 0008 device but that ID
68*4882a593Smuzhiyun 				   shows up in other chips so we use the 5511
69*4882a593Smuzhiyun 				   ID for recognition */
70*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_5597,
71*4882a593Smuzhiyun 	PCI_DEVICE_ID_SI_5598,
72*4882a593Smuzhiyun 	0,			/* terminates the list */
73*4882a593Smuzhiyun };
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun /* Length of ISA address segment */
76*4882a593Smuzhiyun #define SIS5595_EXTENT		8
77*4882a593Smuzhiyun /* SIS5595 SMBus registers */
78*4882a593Smuzhiyun #define SMB_STS_LO		0x00
79*4882a593Smuzhiyun #define SMB_STS_HI		0x01
80*4882a593Smuzhiyun #define SMB_CTL_LO		0x02
81*4882a593Smuzhiyun #define SMB_CTL_HI		0x03
82*4882a593Smuzhiyun #define SMB_ADDR		0x04
83*4882a593Smuzhiyun #define SMB_CMD			0x05
84*4882a593Smuzhiyun #define SMB_PCNT		0x06
85*4882a593Smuzhiyun #define SMB_CNT			0x07
86*4882a593Smuzhiyun #define SMB_BYTE		0x08
87*4882a593Smuzhiyun #define SMB_DEV			0x10
88*4882a593Smuzhiyun #define SMB_DB0			0x11
89*4882a593Smuzhiyun #define SMB_DB1			0x12
90*4882a593Smuzhiyun #define SMB_HAA			0x13
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun /* PCI Address Constants */
93*4882a593Smuzhiyun #define SMB_INDEX		0x38
94*4882a593Smuzhiyun #define SMB_DAT			0x39
95*4882a593Smuzhiyun #define SIS5595_ENABLE_REG	0x40
96*4882a593Smuzhiyun #define ACPI_BASE		0x90
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /* Other settings */
99*4882a593Smuzhiyun #define MAX_TIMEOUT		500
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun /* SIS5595 constants */
102*4882a593Smuzhiyun #define SIS5595_QUICK		0x00
103*4882a593Smuzhiyun #define SIS5595_BYTE		0x02
104*4882a593Smuzhiyun #define SIS5595_BYTE_DATA	0x04
105*4882a593Smuzhiyun #define SIS5595_WORD_DATA	0x06
106*4882a593Smuzhiyun #define SIS5595_PROC_CALL	0x08
107*4882a593Smuzhiyun #define SIS5595_BLOCK_DATA	0x0A
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun /* insmod parameters */
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun /* If force_addr is set to anything different from 0, we forcibly enable
112*4882a593Smuzhiyun    the device at the given address. */
113*4882a593Smuzhiyun static u16 force_addr;
114*4882a593Smuzhiyun module_param_hw(force_addr, ushort, ioport, 0);
115*4882a593Smuzhiyun MODULE_PARM_DESC(force_addr, "Initialize the base address of the i2c controller");
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun static struct pci_driver sis5595_driver;
118*4882a593Smuzhiyun static unsigned short sis5595_base;
119*4882a593Smuzhiyun static struct pci_dev *sis5595_pdev;
120*4882a593Smuzhiyun 
sis5595_read(u8 reg)121*4882a593Smuzhiyun static u8 sis5595_read(u8 reg)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	outb(reg, sis5595_base + SMB_INDEX);
124*4882a593Smuzhiyun 	return inb(sis5595_base + SMB_DAT);
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun 
sis5595_write(u8 reg,u8 data)127*4882a593Smuzhiyun static void sis5595_write(u8 reg, u8 data)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	outb(reg, sis5595_base + SMB_INDEX);
130*4882a593Smuzhiyun 	outb(data, sis5595_base + SMB_DAT);
131*4882a593Smuzhiyun }
132*4882a593Smuzhiyun 
sis5595_setup(struct pci_dev * SIS5595_dev)133*4882a593Smuzhiyun static int sis5595_setup(struct pci_dev *SIS5595_dev)
134*4882a593Smuzhiyun {
135*4882a593Smuzhiyun 	u16 a;
136*4882a593Smuzhiyun 	u8 val;
137*4882a593Smuzhiyun 	int *i;
138*4882a593Smuzhiyun 	int retval;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	/* Look for imposters */
141*4882a593Smuzhiyun 	for (i = blacklist; *i != 0; i++) {
142*4882a593Smuzhiyun 		struct pci_dev *dev;
143*4882a593Smuzhiyun 		dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);
144*4882a593Smuzhiyun 		if (dev) {
145*4882a593Smuzhiyun 			dev_err(&SIS5595_dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);
146*4882a593Smuzhiyun 			pci_dev_put(dev);
147*4882a593Smuzhiyun 			return -ENODEV;
148*4882a593Smuzhiyun 		}
149*4882a593Smuzhiyun 	}
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* Determine the address of the SMBus areas */
152*4882a593Smuzhiyun 	pci_read_config_word(SIS5595_dev, ACPI_BASE, &sis5595_base);
153*4882a593Smuzhiyun 	if (sis5595_base == 0 && force_addr == 0) {
154*4882a593Smuzhiyun 		dev_err(&SIS5595_dev->dev, "ACPI base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
155*4882a593Smuzhiyun 		return -ENODEV;
156*4882a593Smuzhiyun 	}
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	if (force_addr)
159*4882a593Smuzhiyun 		sis5595_base = force_addr & ~(SIS5595_EXTENT - 1);
160*4882a593Smuzhiyun 	dev_dbg(&SIS5595_dev->dev, "ACPI Base address: %04x\n", sis5595_base);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	/* NB: We grab just the two SMBus registers here, but this may still
163*4882a593Smuzhiyun 	 * interfere with ACPI :-(  */
164*4882a593Smuzhiyun 	retval = acpi_check_region(sis5595_base + SMB_INDEX, 2,
165*4882a593Smuzhiyun 				   sis5595_driver.name);
166*4882a593Smuzhiyun 	if (retval)
167*4882a593Smuzhiyun 		return retval;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if (!request_region(sis5595_base + SMB_INDEX, 2,
170*4882a593Smuzhiyun 			    sis5595_driver.name)) {
171*4882a593Smuzhiyun 		dev_err(&SIS5595_dev->dev, "SMBus registers 0x%04x-0x%04x already in use!\n",
172*4882a593Smuzhiyun 			sis5595_base + SMB_INDEX, sis5595_base + SMB_INDEX + 1);
173*4882a593Smuzhiyun 		return -ENODEV;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (force_addr) {
177*4882a593Smuzhiyun 		dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base);
178*4882a593Smuzhiyun 		if (pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base)
179*4882a593Smuzhiyun 		    != PCIBIOS_SUCCESSFUL)
180*4882a593Smuzhiyun 			goto error;
181*4882a593Smuzhiyun 		if (pci_read_config_word(SIS5595_dev, ACPI_BASE, &a)
182*4882a593Smuzhiyun 		    != PCIBIOS_SUCCESSFUL)
183*4882a593Smuzhiyun 			goto error;
184*4882a593Smuzhiyun 		if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) {
185*4882a593Smuzhiyun 			/* doesn't work for some chips! */
186*4882a593Smuzhiyun 			dev_err(&SIS5595_dev->dev, "force address failed - not supported?\n");
187*4882a593Smuzhiyun 			goto error;
188*4882a593Smuzhiyun 		}
189*4882a593Smuzhiyun 	}
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
192*4882a593Smuzhiyun 	    != PCIBIOS_SUCCESSFUL)
193*4882a593Smuzhiyun 		goto error;
194*4882a593Smuzhiyun 	if ((val & 0x80) == 0) {
195*4882a593Smuzhiyun 		dev_info(&SIS5595_dev->dev, "enabling ACPI\n");
196*4882a593Smuzhiyun 		if (pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80)
197*4882a593Smuzhiyun 		    != PCIBIOS_SUCCESSFUL)
198*4882a593Smuzhiyun 			goto error;
199*4882a593Smuzhiyun 		if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val)
200*4882a593Smuzhiyun 		    != PCIBIOS_SUCCESSFUL)
201*4882a593Smuzhiyun 			goto error;
202*4882a593Smuzhiyun 		if ((val & 0x80) == 0) {
203*4882a593Smuzhiyun 			/* doesn't work for some chips? */
204*4882a593Smuzhiyun 			dev_err(&SIS5595_dev->dev, "ACPI enable failed - not supported?\n");
205*4882a593Smuzhiyun 			goto error;
206*4882a593Smuzhiyun 		}
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	/* Everything is happy */
210*4882a593Smuzhiyun 	return 0;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun error:
213*4882a593Smuzhiyun 	release_region(sis5595_base + SMB_INDEX, 2);
214*4882a593Smuzhiyun 	return -ENODEV;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
sis5595_transaction(struct i2c_adapter * adap)217*4882a593Smuzhiyun static int sis5595_transaction(struct i2c_adapter *adap)
218*4882a593Smuzhiyun {
219*4882a593Smuzhiyun 	int temp;
220*4882a593Smuzhiyun 	int result = 0;
221*4882a593Smuzhiyun 	int timeout = 0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	/* Make sure the SMBus host is ready to start transmitting */
224*4882a593Smuzhiyun 	temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
225*4882a593Smuzhiyun 	if (temp != 0x00) {
226*4882a593Smuzhiyun 		dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp);
227*4882a593Smuzhiyun 		sis5595_write(SMB_STS_LO, temp & 0xff);
228*4882a593Smuzhiyun 		sis5595_write(SMB_STS_HI, temp >> 8);
229*4882a593Smuzhiyun 		if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
230*4882a593Smuzhiyun 			dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
231*4882a593Smuzhiyun 			return -EBUSY;
232*4882a593Smuzhiyun 		} else {
233*4882a593Smuzhiyun 			dev_dbg(&adap->dev, "Successful!\n");
234*4882a593Smuzhiyun 		}
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	/* start the transaction by setting bit 4 */
238*4882a593Smuzhiyun 	sis5595_write(SMB_CTL_LO, sis5595_read(SMB_CTL_LO) | 0x10);
239*4882a593Smuzhiyun 
240*4882a593Smuzhiyun 	/* We will always wait for a fraction of a second! */
241*4882a593Smuzhiyun 	do {
242*4882a593Smuzhiyun 		msleep(1);
243*4882a593Smuzhiyun 		temp = sis5595_read(SMB_STS_LO);
244*4882a593Smuzhiyun 	} while (!(temp & 0x40) && (timeout++ < MAX_TIMEOUT));
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	/* If the SMBus is still busy, we give up */
247*4882a593Smuzhiyun 	if (timeout > MAX_TIMEOUT) {
248*4882a593Smuzhiyun 		dev_dbg(&adap->dev, "SMBus Timeout!\n");
249*4882a593Smuzhiyun 		result = -ETIMEDOUT;
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	if (temp & 0x10) {
253*4882a593Smuzhiyun 		dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
254*4882a593Smuzhiyun 		result = -ENXIO;
255*4882a593Smuzhiyun 	}
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	if (temp & 0x20) {
258*4882a593Smuzhiyun 		dev_err(&adap->dev, "Bus collision! SMBus may be locked until "
259*4882a593Smuzhiyun 			"next hard reset (or not...)\n");
260*4882a593Smuzhiyun 		/* Clock stops and slave is stuck in mid-transmission */
261*4882a593Smuzhiyun 		result = -EIO;
262*4882a593Smuzhiyun 	}
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
265*4882a593Smuzhiyun 	if (temp != 0x00) {
266*4882a593Smuzhiyun 		sis5595_write(SMB_STS_LO, temp & 0xff);
267*4882a593Smuzhiyun 		sis5595_write(SMB_STS_HI, temp >> 8);
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
271*4882a593Smuzhiyun 	if (temp != 0x00)
272*4882a593Smuzhiyun 		dev_dbg(&adap->dev, "Failed reset at end of transaction (%02x)\n", temp);
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 	return result;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun /* Return negative errno on error. */
sis5595_access(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)278*4882a593Smuzhiyun static s32 sis5595_access(struct i2c_adapter *adap, u16 addr,
279*4882a593Smuzhiyun 			  unsigned short flags, char read_write,
280*4882a593Smuzhiyun 			  u8 command, int size, union i2c_smbus_data *data)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	int status;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	switch (size) {
285*4882a593Smuzhiyun 	case I2C_SMBUS_QUICK:
286*4882a593Smuzhiyun 		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
287*4882a593Smuzhiyun 		size = SIS5595_QUICK;
288*4882a593Smuzhiyun 		break;
289*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE:
290*4882a593Smuzhiyun 		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
291*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE)
292*4882a593Smuzhiyun 			sis5595_write(SMB_CMD, command);
293*4882a593Smuzhiyun 		size = SIS5595_BYTE;
294*4882a593Smuzhiyun 		break;
295*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE_DATA:
296*4882a593Smuzhiyun 		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
297*4882a593Smuzhiyun 		sis5595_write(SMB_CMD, command);
298*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE)
299*4882a593Smuzhiyun 			sis5595_write(SMB_BYTE, data->byte);
300*4882a593Smuzhiyun 		size = SIS5595_BYTE_DATA;
301*4882a593Smuzhiyun 		break;
302*4882a593Smuzhiyun 	case I2C_SMBUS_PROC_CALL:
303*4882a593Smuzhiyun 	case I2C_SMBUS_WORD_DATA:
304*4882a593Smuzhiyun 		sis5595_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
305*4882a593Smuzhiyun 		sis5595_write(SMB_CMD, command);
306*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
307*4882a593Smuzhiyun 			sis5595_write(SMB_BYTE, data->word & 0xff);
308*4882a593Smuzhiyun 			sis5595_write(SMB_BYTE + 1,
309*4882a593Smuzhiyun 				      (data->word & 0xff00) >> 8);
310*4882a593Smuzhiyun 		}
311*4882a593Smuzhiyun 		size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA;
312*4882a593Smuzhiyun 		break;
313*4882a593Smuzhiyun 	default:
314*4882a593Smuzhiyun 		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
315*4882a593Smuzhiyun 		return -EOPNOTSUPP;
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	sis5595_write(SMB_CTL_LO, ((size & 0x0E)));
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	status = sis5595_transaction(adap);
321*4882a593Smuzhiyun 	if (status)
322*4882a593Smuzhiyun 		return status;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	if ((size != SIS5595_PROC_CALL) &&
325*4882a593Smuzhiyun 	    ((read_write == I2C_SMBUS_WRITE) || (size == SIS5595_QUICK)))
326*4882a593Smuzhiyun 		return 0;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	switch (size) {
330*4882a593Smuzhiyun 	case SIS5595_BYTE:
331*4882a593Smuzhiyun 	case SIS5595_BYTE_DATA:
332*4882a593Smuzhiyun 		data->byte = sis5595_read(SMB_BYTE);
333*4882a593Smuzhiyun 		break;
334*4882a593Smuzhiyun 	case SIS5595_WORD_DATA:
335*4882a593Smuzhiyun 	case SIS5595_PROC_CALL:
336*4882a593Smuzhiyun 		data->word = sis5595_read(SMB_BYTE) + (sis5595_read(SMB_BYTE + 1) << 8);
337*4882a593Smuzhiyun 		break;
338*4882a593Smuzhiyun 	}
339*4882a593Smuzhiyun 	return 0;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun 
sis5595_func(struct i2c_adapter * adapter)342*4882a593Smuzhiyun static u32 sis5595_func(struct i2c_adapter *adapter)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
345*4882a593Smuzhiyun 	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
346*4882a593Smuzhiyun 	    I2C_FUNC_SMBUS_PROC_CALL;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun static const struct i2c_algorithm smbus_algorithm = {
350*4882a593Smuzhiyun 	.smbus_xfer	= sis5595_access,
351*4882a593Smuzhiyun 	.functionality	= sis5595_func,
352*4882a593Smuzhiyun };
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun static struct i2c_adapter sis5595_adapter = {
355*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
356*4882a593Smuzhiyun 	.class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
357*4882a593Smuzhiyun 	.algo		= &smbus_algorithm,
358*4882a593Smuzhiyun };
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun static const struct pci_device_id sis5595_ids[] = {
361*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
362*4882a593Smuzhiyun 	{ 0, }
363*4882a593Smuzhiyun };
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun MODULE_DEVICE_TABLE (pci, sis5595_ids);
366*4882a593Smuzhiyun 
sis5595_probe(struct pci_dev * dev,const struct pci_device_id * id)367*4882a593Smuzhiyun static int sis5595_probe(struct pci_dev *dev, const struct pci_device_id *id)
368*4882a593Smuzhiyun {
369*4882a593Smuzhiyun 	int err;
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun 	if (sis5595_setup(dev)) {
372*4882a593Smuzhiyun 		dev_err(&dev->dev, "SIS5595 not detected, module not inserted.\n");
373*4882a593Smuzhiyun 		return -ENODEV;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	/* set up the sysfs linkage to our parent device */
377*4882a593Smuzhiyun 	sis5595_adapter.dev.parent = &dev->dev;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	snprintf(sis5595_adapter.name, sizeof(sis5595_adapter.name),
380*4882a593Smuzhiyun 		 "SMBus SIS5595 adapter at %04x", sis5595_base + SMB_INDEX);
381*4882a593Smuzhiyun 	err = i2c_add_adapter(&sis5595_adapter);
382*4882a593Smuzhiyun 	if (err) {
383*4882a593Smuzhiyun 		release_region(sis5595_base + SMB_INDEX, 2);
384*4882a593Smuzhiyun 		return err;
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	/* Always return failure here.  This is to allow other drivers to bind
388*4882a593Smuzhiyun 	 * to this pci device.  We don't really want to have control over the
389*4882a593Smuzhiyun 	 * pci device, we only wanted to read as few register values from it.
390*4882a593Smuzhiyun 	 */
391*4882a593Smuzhiyun 	sis5595_pdev =  pci_dev_get(dev);
392*4882a593Smuzhiyun 	return -ENODEV;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun static struct pci_driver sis5595_driver = {
396*4882a593Smuzhiyun 	.name		= "sis5595_smbus",
397*4882a593Smuzhiyun 	.id_table	= sis5595_ids,
398*4882a593Smuzhiyun 	.probe		= sis5595_probe,
399*4882a593Smuzhiyun };
400*4882a593Smuzhiyun 
i2c_sis5595_init(void)401*4882a593Smuzhiyun static int __init i2c_sis5595_init(void)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun 	return pci_register_driver(&sis5595_driver);
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun 
i2c_sis5595_exit(void)406*4882a593Smuzhiyun static void __exit i2c_sis5595_exit(void)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	pci_unregister_driver(&sis5595_driver);
409*4882a593Smuzhiyun 	if (sis5595_pdev) {
410*4882a593Smuzhiyun 		i2c_del_adapter(&sis5595_adapter);
411*4882a593Smuzhiyun 		release_region(sis5595_base + SMB_INDEX, 2);
412*4882a593Smuzhiyun 		pci_dev_put(sis5595_pdev);
413*4882a593Smuzhiyun 		sis5595_pdev = NULL;
414*4882a593Smuzhiyun 	}
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>");
418*4882a593Smuzhiyun MODULE_DESCRIPTION("SIS5595 SMBus driver");
419*4882a593Smuzhiyun MODULE_LICENSE("GPL");
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun module_init(i2c_sis5595_init);
422*4882a593Smuzhiyun module_exit(i2c_sis5595_exit);
423