xref: /OK3568_Linux_fs/kernel/drivers/i2c/busses/i2c-nforce2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun     SMBus driver for nVidia nForce2 MCP
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun     Added nForce3 Pro 150  Thomas Leibold <thomas@plx.com>,
6*4882a593Smuzhiyun 	Ported to 2.5 Patrick Dreker <patrick@dreker.de>,
7*4882a593Smuzhiyun     Copyright (c) 2003  Hans-Frieder Vogt <hfvogt@arcor.de>,
8*4882a593Smuzhiyun     Based on
9*4882a593Smuzhiyun     SMBus 2.0 driver for AMD-8111 IO-Hub
10*4882a593Smuzhiyun     Copyright (c) 2002 Vojtech Pavlik
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun /*
15*4882a593Smuzhiyun     SUPPORTED DEVICES		PCI ID
16*4882a593Smuzhiyun     nForce2 MCP			0064
17*4882a593Smuzhiyun     nForce2 Ultra 400 MCP	0084
18*4882a593Smuzhiyun     nForce3 Pro150 MCP		00D4
19*4882a593Smuzhiyun     nForce3 250Gb MCP		00E4
20*4882a593Smuzhiyun     nForce4 MCP			0052
21*4882a593Smuzhiyun     nForce4 MCP-04		0034
22*4882a593Smuzhiyun     nForce MCP51		0264
23*4882a593Smuzhiyun     nForce MCP55		0368
24*4882a593Smuzhiyun     nForce MCP61		03EB
25*4882a593Smuzhiyun     nForce MCP65		0446
26*4882a593Smuzhiyun     nForce MCP67		0542
27*4882a593Smuzhiyun     nForce MCP73		07D8
28*4882a593Smuzhiyun     nForce MCP78S		0752
29*4882a593Smuzhiyun     nForce MCP79		0AA2
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun     This driver supports the 2 SMBuses that are included in the MCP of the
32*4882a593Smuzhiyun     nForce2/3/4/5xx chipsets.
33*4882a593Smuzhiyun */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* Note: we assume there can only be one nForce2, with two SMBus interfaces */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include <linux/module.h>
38*4882a593Smuzhiyun #include <linux/pci.h>
39*4882a593Smuzhiyun #include <linux/kernel.h>
40*4882a593Smuzhiyun #include <linux/stddef.h>
41*4882a593Smuzhiyun #include <linux/ioport.h>
42*4882a593Smuzhiyun #include <linux/i2c.h>
43*4882a593Smuzhiyun #include <linux/delay.h>
44*4882a593Smuzhiyun #include <linux/dmi.h>
45*4882a593Smuzhiyun #include <linux/acpi.h>
46*4882a593Smuzhiyun #include <linux/slab.h>
47*4882a593Smuzhiyun #include <linux/io.h>
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun MODULE_LICENSE("GPL");
50*4882a593Smuzhiyun MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>");
51*4882a593Smuzhiyun MODULE_DESCRIPTION("nForce2/3/4/5xx SMBus driver");
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun struct nforce2_smbus {
55*4882a593Smuzhiyun 	struct i2c_adapter adapter;
56*4882a593Smuzhiyun 	int base;
57*4882a593Smuzhiyun 	int size;
58*4882a593Smuzhiyun 	int blockops;
59*4882a593Smuzhiyun 	int can_abort;
60*4882a593Smuzhiyun };
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun /*
64*4882a593Smuzhiyun  * nVidia nForce2 SMBus control register definitions
65*4882a593Smuzhiyun  * (Newer incarnations use standard BARs 4 and 5 instead)
66*4882a593Smuzhiyun  */
67*4882a593Smuzhiyun #define NFORCE_PCI_SMB1	0x50
68*4882a593Smuzhiyun #define NFORCE_PCI_SMB2	0x54
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /*
72*4882a593Smuzhiyun  * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
73*4882a593Smuzhiyun  */
74*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL	(smbus->base + 0x00)	/* protocol, PEC */
75*4882a593Smuzhiyun #define NVIDIA_SMB_STS		(smbus->base + 0x01)	/* status */
76*4882a593Smuzhiyun #define NVIDIA_SMB_ADDR		(smbus->base + 0x02)	/* address */
77*4882a593Smuzhiyun #define NVIDIA_SMB_CMD		(smbus->base + 0x03)	/* command */
78*4882a593Smuzhiyun #define NVIDIA_SMB_DATA		(smbus->base + 0x04)	/* 32 data registers */
79*4882a593Smuzhiyun #define NVIDIA_SMB_BCNT		(smbus->base + 0x24)	/* number of data
80*4882a593Smuzhiyun 							   bytes */
81*4882a593Smuzhiyun #define NVIDIA_SMB_STATUS_ABRT	(smbus->base + 0x3c)	/* register used to
82*4882a593Smuzhiyun 							   check the status of
83*4882a593Smuzhiyun 							   the abort command */
84*4882a593Smuzhiyun #define NVIDIA_SMB_CTRL		(smbus->base + 0x3e)	/* control register */
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun #define NVIDIA_SMB_STATUS_ABRT_STS	0x01		/* Bit to notify that
87*4882a593Smuzhiyun 							   abort succeeded */
88*4882a593Smuzhiyun #define NVIDIA_SMB_CTRL_ABORT	0x20
89*4882a593Smuzhiyun #define NVIDIA_SMB_STS_DONE	0x80
90*4882a593Smuzhiyun #define NVIDIA_SMB_STS_ALRM	0x40
91*4882a593Smuzhiyun #define NVIDIA_SMB_STS_RES	0x20
92*4882a593Smuzhiyun #define NVIDIA_SMB_STS_STATUS	0x1f
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_WRITE			0x00
95*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_READ			0x01
96*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_QUICK			0x02
97*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_BYTE			0x04
98*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_BYTE_DATA		0x06
99*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_WORD_DATA		0x08
100*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_BLOCK_DATA		0x0a
101*4882a593Smuzhiyun #define NVIDIA_SMB_PRTCL_PEC			0x80
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /* Misc definitions */
104*4882a593Smuzhiyun #define MAX_TIMEOUT	100
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* We disable the second SMBus channel on these boards */
107*4882a593Smuzhiyun static const struct dmi_system_id nforce2_dmi_blacklist2[] = {
108*4882a593Smuzhiyun 	{
109*4882a593Smuzhiyun 		.ident = "DFI Lanparty NF4 Expert",
110*4882a593Smuzhiyun 		.matches = {
111*4882a593Smuzhiyun 			DMI_MATCH(DMI_BOARD_VENDOR, "DFI Corp,LTD"),
112*4882a593Smuzhiyun 			DMI_MATCH(DMI_BOARD_NAME, "LP UT NF4 Expert"),
113*4882a593Smuzhiyun 		},
114*4882a593Smuzhiyun 	},
115*4882a593Smuzhiyun 	{ }
116*4882a593Smuzhiyun };
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun static struct pci_driver nforce2_driver;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /* For multiplexing support, we need a global reference to the 1st
121*4882a593Smuzhiyun    SMBus channel */
122*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985)
123*4882a593Smuzhiyun struct i2c_adapter *nforce2_smbus;
124*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nforce2_smbus);
125*4882a593Smuzhiyun 
nforce2_set_reference(struct i2c_adapter * adap)126*4882a593Smuzhiyun static void nforce2_set_reference(struct i2c_adapter *adap)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	nforce2_smbus = adap;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun #else
nforce2_set_reference(struct i2c_adapter * adap)131*4882a593Smuzhiyun static inline void nforce2_set_reference(struct i2c_adapter *adap) { }
132*4882a593Smuzhiyun #endif
133*4882a593Smuzhiyun 
nforce2_abort(struct i2c_adapter * adap)134*4882a593Smuzhiyun static void nforce2_abort(struct i2c_adapter *adap)
135*4882a593Smuzhiyun {
136*4882a593Smuzhiyun 	struct nforce2_smbus *smbus = adap->algo_data;
137*4882a593Smuzhiyun 	int timeout = 0;
138*4882a593Smuzhiyun 	unsigned char temp;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	dev_dbg(&adap->dev, "Aborting current transaction\n");
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	outb_p(NVIDIA_SMB_CTRL_ABORT, NVIDIA_SMB_CTRL);
143*4882a593Smuzhiyun 	do {
144*4882a593Smuzhiyun 		msleep(1);
145*4882a593Smuzhiyun 		temp = inb_p(NVIDIA_SMB_STATUS_ABRT);
146*4882a593Smuzhiyun 	} while (!(temp & NVIDIA_SMB_STATUS_ABRT_STS) &&
147*4882a593Smuzhiyun 			(timeout++ < MAX_TIMEOUT));
148*4882a593Smuzhiyun 	if (!(temp & NVIDIA_SMB_STATUS_ABRT_STS))
149*4882a593Smuzhiyun 		dev_err(&adap->dev, "Can't reset the smbus\n");
150*4882a593Smuzhiyun 	outb_p(NVIDIA_SMB_STATUS_ABRT_STS, NVIDIA_SMB_STATUS_ABRT);
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
nforce2_check_status(struct i2c_adapter * adap)153*4882a593Smuzhiyun static int nforce2_check_status(struct i2c_adapter *adap)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	struct nforce2_smbus *smbus = adap->algo_data;
156*4882a593Smuzhiyun 	int timeout = 0;
157*4882a593Smuzhiyun 	unsigned char temp;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	do {
160*4882a593Smuzhiyun 		msleep(1);
161*4882a593Smuzhiyun 		temp = inb_p(NVIDIA_SMB_STS);
162*4882a593Smuzhiyun 	} while ((!temp) && (timeout++ < MAX_TIMEOUT));
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	if (timeout > MAX_TIMEOUT) {
165*4882a593Smuzhiyun 		dev_dbg(&adap->dev, "SMBus Timeout!\n");
166*4882a593Smuzhiyun 		if (smbus->can_abort)
167*4882a593Smuzhiyun 			nforce2_abort(adap);
168*4882a593Smuzhiyun 		return -ETIMEDOUT;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 	if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
171*4882a593Smuzhiyun 		dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp);
172*4882a593Smuzhiyun 		return -EIO;
173*4882a593Smuzhiyun 	}
174*4882a593Smuzhiyun 	return 0;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun /* Return negative errno on error */
nforce2_access(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)178*4882a593Smuzhiyun static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
179*4882a593Smuzhiyun 		unsigned short flags, char read_write,
180*4882a593Smuzhiyun 		u8 command, int size, union i2c_smbus_data *data)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct nforce2_smbus *smbus = adap->algo_data;
183*4882a593Smuzhiyun 	unsigned char protocol, pec;
184*4882a593Smuzhiyun 	u8 len;
185*4882a593Smuzhiyun 	int i, status;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
188*4882a593Smuzhiyun 		NVIDIA_SMB_PRTCL_WRITE;
189*4882a593Smuzhiyun 	pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	switch (size) {
192*4882a593Smuzhiyun 	case I2C_SMBUS_QUICK:
193*4882a593Smuzhiyun 		protocol |= NVIDIA_SMB_PRTCL_QUICK;
194*4882a593Smuzhiyun 		read_write = I2C_SMBUS_WRITE;
195*4882a593Smuzhiyun 		break;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE:
198*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE)
199*4882a593Smuzhiyun 			outb_p(command, NVIDIA_SMB_CMD);
200*4882a593Smuzhiyun 		protocol |= NVIDIA_SMB_PRTCL_BYTE;
201*4882a593Smuzhiyun 		break;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE_DATA:
204*4882a593Smuzhiyun 		outb_p(command, NVIDIA_SMB_CMD);
205*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE)
206*4882a593Smuzhiyun 			outb_p(data->byte, NVIDIA_SMB_DATA);
207*4882a593Smuzhiyun 		protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
208*4882a593Smuzhiyun 		break;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	case I2C_SMBUS_WORD_DATA:
211*4882a593Smuzhiyun 		outb_p(command, NVIDIA_SMB_CMD);
212*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
213*4882a593Smuzhiyun 			outb_p(data->word, NVIDIA_SMB_DATA);
214*4882a593Smuzhiyun 			outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1);
215*4882a593Smuzhiyun 		}
216*4882a593Smuzhiyun 		protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
217*4882a593Smuzhiyun 		break;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	case I2C_SMBUS_BLOCK_DATA:
220*4882a593Smuzhiyun 		outb_p(command, NVIDIA_SMB_CMD);
221*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
222*4882a593Smuzhiyun 			len = data->block[0];
223*4882a593Smuzhiyun 			if ((len == 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
224*4882a593Smuzhiyun 				dev_err(&adap->dev,
225*4882a593Smuzhiyun 					"Transaction failed (requested block size: %d)\n",
226*4882a593Smuzhiyun 					len);
227*4882a593Smuzhiyun 				return -EINVAL;
228*4882a593Smuzhiyun 			}
229*4882a593Smuzhiyun 			outb_p(len, NVIDIA_SMB_BCNT);
230*4882a593Smuzhiyun 			for (i = 0; i < I2C_SMBUS_BLOCK_MAX; i++)
231*4882a593Smuzhiyun 				outb_p(data->block[i + 1],
232*4882a593Smuzhiyun 				       NVIDIA_SMB_DATA + i);
233*4882a593Smuzhiyun 		}
234*4882a593Smuzhiyun 		protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
235*4882a593Smuzhiyun 		break;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	default:
238*4882a593Smuzhiyun 		dev_err(&adap->dev, "Unsupported transaction %d\n", size);
239*4882a593Smuzhiyun 		return -EOPNOTSUPP;
240*4882a593Smuzhiyun 	}
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
243*4882a593Smuzhiyun 	outb_p(protocol, NVIDIA_SMB_PRTCL);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	status = nforce2_check_status(adap);
246*4882a593Smuzhiyun 	if (status)
247*4882a593Smuzhiyun 		return status;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	if (read_write == I2C_SMBUS_WRITE)
250*4882a593Smuzhiyun 		return 0;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	switch (size) {
253*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE:
254*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE_DATA:
255*4882a593Smuzhiyun 		data->byte = inb_p(NVIDIA_SMB_DATA);
256*4882a593Smuzhiyun 		break;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	case I2C_SMBUS_WORD_DATA:
259*4882a593Smuzhiyun 		data->word = inb_p(NVIDIA_SMB_DATA) |
260*4882a593Smuzhiyun 			     (inb_p(NVIDIA_SMB_DATA + 1) << 8);
261*4882a593Smuzhiyun 		break;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	case I2C_SMBUS_BLOCK_DATA:
264*4882a593Smuzhiyun 		len = inb_p(NVIDIA_SMB_BCNT);
265*4882a593Smuzhiyun 		if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) {
266*4882a593Smuzhiyun 			dev_err(&adap->dev,
267*4882a593Smuzhiyun 				"Transaction failed (received block size: 0x%02x)\n",
268*4882a593Smuzhiyun 				len);
269*4882a593Smuzhiyun 			return -EPROTO;
270*4882a593Smuzhiyun 		}
271*4882a593Smuzhiyun 		for (i = 0; i < len; i++)
272*4882a593Smuzhiyun 			data->block[i + 1] = inb_p(NVIDIA_SMB_DATA + i);
273*4882a593Smuzhiyun 		data->block[0] = len;
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	}
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	return 0;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 
nforce2_func(struct i2c_adapter * adapter)281*4882a593Smuzhiyun static u32 nforce2_func(struct i2c_adapter *adapter)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	/* other functionality might be possible, but is not tested */
284*4882a593Smuzhiyun 	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
285*4882a593Smuzhiyun 	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
286*4882a593Smuzhiyun 	       I2C_FUNC_SMBUS_PEC |
287*4882a593Smuzhiyun 	       (((struct nforce2_smbus *)adapter->algo_data)->blockops ?
288*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_BLOCK_DATA : 0);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun static const struct i2c_algorithm smbus_algorithm = {
292*4882a593Smuzhiyun 	.smbus_xfer	= nforce2_access,
293*4882a593Smuzhiyun 	.functionality	= nforce2_func,
294*4882a593Smuzhiyun };
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun static const struct pci_device_id nforce2_ids[] = {
298*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
299*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
300*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
301*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
302*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
303*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
304*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS) },
305*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS) },
306*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS) },
307*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS) },
308*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS) },
309*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS) },
310*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS) },
311*4882a593Smuzhiyun 	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS) },
312*4882a593Smuzhiyun 	{ 0 }
313*4882a593Smuzhiyun };
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, nforce2_ids);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 
nforce2_probe_smb(struct pci_dev * dev,int bar,int alt_reg,struct nforce2_smbus * smbus,const char * name)318*4882a593Smuzhiyun static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg,
319*4882a593Smuzhiyun 			     struct nforce2_smbus *smbus, const char *name)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	int error;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	smbus->base = pci_resource_start(dev, bar);
324*4882a593Smuzhiyun 	if (smbus->base) {
325*4882a593Smuzhiyun 		smbus->size = pci_resource_len(dev, bar);
326*4882a593Smuzhiyun 	} else {
327*4882a593Smuzhiyun 		/* Older incarnations of the device used non-standard BARs */
328*4882a593Smuzhiyun 		u16 iobase;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 		if (pci_read_config_word(dev, alt_reg, &iobase)
331*4882a593Smuzhiyun 		    != PCIBIOS_SUCCESSFUL) {
332*4882a593Smuzhiyun 			dev_err(&dev->dev, "Error reading PCI config for %s\n",
333*4882a593Smuzhiyun 				name);
334*4882a593Smuzhiyun 			return -EIO;
335*4882a593Smuzhiyun 		}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 		smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
338*4882a593Smuzhiyun 		smbus->size = 64;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun 	error = acpi_check_region(smbus->base, smbus->size,
342*4882a593Smuzhiyun 				  nforce2_driver.name);
343*4882a593Smuzhiyun 	if (error)
344*4882a593Smuzhiyun 		return error;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
347*4882a593Smuzhiyun 		dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
348*4882a593Smuzhiyun 			smbus->base, smbus->base+smbus->size-1, name);
349*4882a593Smuzhiyun 		return -EBUSY;
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun 	smbus->adapter.owner = THIS_MODULE;
352*4882a593Smuzhiyun 	smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
353*4882a593Smuzhiyun 	smbus->adapter.algo = &smbus_algorithm;
354*4882a593Smuzhiyun 	smbus->adapter.algo_data = smbus;
355*4882a593Smuzhiyun 	smbus->adapter.dev.parent = &dev->dev;
356*4882a593Smuzhiyun 	snprintf(smbus->adapter.name, sizeof(smbus->adapter.name),
357*4882a593Smuzhiyun 		"SMBus nForce2 adapter at %04x", smbus->base);
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	error = i2c_add_adapter(&smbus->adapter);
360*4882a593Smuzhiyun 	if (error) {
361*4882a593Smuzhiyun 		release_region(smbus->base, smbus->size);
362*4882a593Smuzhiyun 		return error;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 	dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n",
365*4882a593Smuzhiyun 		smbus->base);
366*4882a593Smuzhiyun 	return 0;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 
nforce2_probe(struct pci_dev * dev,const struct pci_device_id * id)370*4882a593Smuzhiyun static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	struct nforce2_smbus *smbuses;
373*4882a593Smuzhiyun 	int res1, res2;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	/* we support 2 SMBus adapters */
376*4882a593Smuzhiyun 	smbuses = kcalloc(2, sizeof(struct nforce2_smbus), GFP_KERNEL);
377*4882a593Smuzhiyun 	if (!smbuses)
378*4882a593Smuzhiyun 		return -ENOMEM;
379*4882a593Smuzhiyun 	pci_set_drvdata(dev, smbuses);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	switch (dev->device) {
382*4882a593Smuzhiyun 	case PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS:
383*4882a593Smuzhiyun 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS:
384*4882a593Smuzhiyun 	case PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS:
385*4882a593Smuzhiyun 		smbuses[0].blockops = 1;
386*4882a593Smuzhiyun 		smbuses[1].blockops = 1;
387*4882a593Smuzhiyun 		smbuses[0].can_abort = 1;
388*4882a593Smuzhiyun 		smbuses[1].can_abort = 1;
389*4882a593Smuzhiyun 	}
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	/* SMBus adapter 1 */
392*4882a593Smuzhiyun 	res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
393*4882a593Smuzhiyun 	if (res1 < 0)
394*4882a593Smuzhiyun 		smbuses[0].base = 0;	/* to have a check value */
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	/* SMBus adapter 2 */
397*4882a593Smuzhiyun 	if (dmi_check_system(nforce2_dmi_blacklist2)) {
398*4882a593Smuzhiyun 		dev_err(&dev->dev, "Disabling SMB2 for safety reasons.\n");
399*4882a593Smuzhiyun 		res2 = -EPERM;
400*4882a593Smuzhiyun 		smbuses[1].base = 0;
401*4882a593Smuzhiyun 	} else {
402*4882a593Smuzhiyun 		res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1],
403*4882a593Smuzhiyun 					 "SMB2");
404*4882a593Smuzhiyun 		if (res2 < 0)
405*4882a593Smuzhiyun 			smbuses[1].base = 0;	/* to have a check value */
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if ((res1 < 0) && (res2 < 0)) {
409*4882a593Smuzhiyun 		/* we did not find even one of the SMBuses, so we give up */
410*4882a593Smuzhiyun 		kfree(smbuses);
411*4882a593Smuzhiyun 		return -ENODEV;
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	nforce2_set_reference(&smbuses[0].adapter);
415*4882a593Smuzhiyun 	return 0;
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 
nforce2_remove(struct pci_dev * dev)419*4882a593Smuzhiyun static void nforce2_remove(struct pci_dev *dev)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	struct nforce2_smbus *smbuses = pci_get_drvdata(dev);
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	nforce2_set_reference(NULL);
424*4882a593Smuzhiyun 	if (smbuses[0].base) {
425*4882a593Smuzhiyun 		i2c_del_adapter(&smbuses[0].adapter);
426*4882a593Smuzhiyun 		release_region(smbuses[0].base, smbuses[0].size);
427*4882a593Smuzhiyun 	}
428*4882a593Smuzhiyun 	if (smbuses[1].base) {
429*4882a593Smuzhiyun 		i2c_del_adapter(&smbuses[1].adapter);
430*4882a593Smuzhiyun 		release_region(smbuses[1].base, smbuses[1].size);
431*4882a593Smuzhiyun 	}
432*4882a593Smuzhiyun 	kfree(smbuses);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun static struct pci_driver nforce2_driver = {
436*4882a593Smuzhiyun 	.name		= "nForce2_smbus",
437*4882a593Smuzhiyun 	.id_table	= nforce2_ids,
438*4882a593Smuzhiyun 	.probe		= nforce2_probe,
439*4882a593Smuzhiyun 	.remove		= nforce2_remove,
440*4882a593Smuzhiyun };
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun module_pci_driver(nforce2_driver);
443