blob: 2d80eb26f688ac687e956841ecca1112cdeb8b15 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 SMBus driver for nVidia nForce2 MCP
3
4 Added nForce3 Pro 150 Thomas Leibold <thomas@plx.com>,
5 Ported to 2.5 Patrick Dreker <patrick@dreker.de>,
6 Copyright (c) 2003 Hans-Frieder Vogt <hfvogt@arcor.de>,
7 Based on
8 SMBus 2.0 driver for AMD-8111 IO-Hub
9 Copyright (c) 2002 Vojtech Pavlik
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24*/
25
26/*
27 SUPPORTED DEVICES PCI ID
28 nForce2 MCP 0064
29 nForce2 Ultra 400 MCP 0084
30 nForce3 Pro150 MCP 00D4
31 nForce3 250Gb MCP 00E4
32 nForce4 MCP 0052
Jean Delvare7c72ccf2005-12-18 17:25:18 +010033 nForce4 MCP-04 0034
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
35 This driver supports the 2 SMBuses that are included in the MCP of the
36 nForce2/3/4 chipsets.
37*/
38
39/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/module.h>
42#include <linux/pci.h>
43#include <linux/kernel.h>
44#include <linux/stddef.h>
45#include <linux/sched.h>
46#include <linux/ioport.h>
47#include <linux/init.h>
48#include <linux/i2c.h>
49#include <linux/delay.h>
50#include <asm/io.h>
51
52MODULE_LICENSE("GPL");
53MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
54MODULE_DESCRIPTION("nForce2 SMBus driver");
55
56
57struct nforce2_smbus {
58 struct pci_dev *dev;
59 struct i2c_adapter adapter;
60 int base;
61 int size;
62};
63
64
65/*
66 * nVidia nForce2 SMBus control register definitions
67 */
68#define NFORCE_PCI_SMB1 0x50
69#define NFORCE_PCI_SMB2 0x54
70
71
72/*
73 * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
74 */
75#define NVIDIA_SMB_PRTCL (smbus->base + 0x00) /* protocol, PEC */
76#define NVIDIA_SMB_STS (smbus->base + 0x01) /* status */
77#define NVIDIA_SMB_ADDR (smbus->base + 0x02) /* address */
78#define NVIDIA_SMB_CMD (smbus->base + 0x03) /* command */
79#define NVIDIA_SMB_DATA (smbus->base + 0x04) /* 32 data registers */
80#define NVIDIA_SMB_BCNT (smbus->base + 0x24) /* number of data bytes */
81#define NVIDIA_SMB_ALRM_A (smbus->base + 0x25) /* alarm address */
82#define NVIDIA_SMB_ALRM_D (smbus->base + 0x26) /* 2 bytes alarm data */
83
84#define NVIDIA_SMB_STS_DONE 0x80
85#define NVIDIA_SMB_STS_ALRM 0x40
86#define NVIDIA_SMB_STS_RES 0x20
87#define NVIDIA_SMB_STS_STATUS 0x1f
88
89#define NVIDIA_SMB_PRTCL_WRITE 0x00
90#define NVIDIA_SMB_PRTCL_READ 0x01
91#define NVIDIA_SMB_PRTCL_QUICK 0x02
92#define NVIDIA_SMB_PRTCL_BYTE 0x04
93#define NVIDIA_SMB_PRTCL_BYTE_DATA 0x06
94#define NVIDIA_SMB_PRTCL_WORD_DATA 0x08
95#define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a
96#define NVIDIA_SMB_PRTCL_PROC_CALL 0x0c
97#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL 0x0d
98#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA 0x4a
99#define NVIDIA_SMB_PRTCL_PEC 0x80
100
Jean Delvared6072f82005-09-25 16:37:04 +0200101static struct pci_driver nforce2_driver;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
104 unsigned short flags, char read_write,
105 u8 command, int size, union i2c_smbus_data *data);
106static u32 nforce2_func(struct i2c_adapter *adapter);
107
108
109static struct i2c_algorithm smbus_algorithm = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 .smbus_xfer = nforce2_access,
111 .functionality = nforce2_func,
112};
113
114static struct i2c_adapter nforce2_adapter = {
115 .owner = THIS_MODULE,
116 .class = I2C_CLASS_HWMON,
117 .algo = &smbus_algorithm,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118};
119
120/* Return -1 on error. See smbus.h for more information */
121static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
122 unsigned short flags, char read_write,
123 u8 command, int size, union i2c_smbus_data * data)
124{
125 struct nforce2_smbus *smbus = adap->algo_data;
126 unsigned char protocol, pec, temp;
127 unsigned char len = 0; /* to keep the compiler quiet */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 int i;
129
130 protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
131 NVIDIA_SMB_PRTCL_WRITE;
132 pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
133
134 switch (size) {
135
136 case I2C_SMBUS_QUICK:
137 protocol |= NVIDIA_SMB_PRTCL_QUICK;
138 read_write = I2C_SMBUS_WRITE;
139 break;
140
141 case I2C_SMBUS_BYTE:
142 if (read_write == I2C_SMBUS_WRITE)
143 outb_p(command, NVIDIA_SMB_CMD);
144 protocol |= NVIDIA_SMB_PRTCL_BYTE;
145 break;
146
147 case I2C_SMBUS_BYTE_DATA:
148 outb_p(command, NVIDIA_SMB_CMD);
149 if (read_write == I2C_SMBUS_WRITE)
150 outb_p(data->byte, NVIDIA_SMB_DATA);
151 protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
152 break;
153
154 case I2C_SMBUS_WORD_DATA:
155 outb_p(command, NVIDIA_SMB_CMD);
156 if (read_write == I2C_SMBUS_WRITE) {
157 outb_p(data->word, NVIDIA_SMB_DATA);
158 outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);
159 }
160 protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
161 break;
162
163 case I2C_SMBUS_BLOCK_DATA:
164 outb_p(command, NVIDIA_SMB_CMD);
165 if (read_write == I2C_SMBUS_WRITE) {
166 len = min_t(u8, data->block[0], 32);
167 outb_p(len, NVIDIA_SMB_BCNT);
168 for (i = 0; i < len; i++)
169 outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
170 }
171 protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
172 break;
173
174 case I2C_SMBUS_I2C_BLOCK_DATA:
175 len = min_t(u8, data->block[0], 32);
176 outb_p(command, NVIDIA_SMB_CMD);
177 outb_p(len, NVIDIA_SMB_BCNT);
178 if (read_write == I2C_SMBUS_WRITE)
179 for (i = 0; i < len; i++)
180 outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
181 protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
182 break;
183
184 case I2C_SMBUS_PROC_CALL:
185 dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
186 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
188 case I2C_SMBUS_BLOCK_PROC_CALL:
189 dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
190 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 default:
193 dev_err(&adap->dev, "Unsupported transaction %d\n", size);
194 return -1;
195 }
196
197 outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
198 outb_p(protocol, NVIDIA_SMB_PRTCL);
199
200 temp = inb_p(NVIDIA_SMB_STS);
201
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 if (~temp & NVIDIA_SMB_STS_DONE) {
203 udelay(500);
204 temp = inb_p(NVIDIA_SMB_STS);
205 }
206 if (~temp & NVIDIA_SMB_STS_DONE) {
207 msleep(10);
208 temp = inb_p(NVIDIA_SMB_STS);
209 }
210
Hans-Frieder Vogt50330172005-07-23 15:33:39 +0200211 if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
212 dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 return -1;
Hans-Frieder Vogt50330172005-07-23 15:33:39 +0200214 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
216 if (read_write == I2C_SMBUS_WRITE)
217 return 0;
218
219 switch (size) {
220
221 case I2C_SMBUS_BYTE:
222 case I2C_SMBUS_BYTE_DATA:
223 data->byte = inb_p(NVIDIA_SMB_DATA);
224 break;
225
226 case I2C_SMBUS_WORD_DATA:
227 /* case I2C_SMBUS_PROC_CALL: not supported */
228 data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
229 break;
230
231 case I2C_SMBUS_BLOCK_DATA:
232 /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
233 len = inb_p(NVIDIA_SMB_BCNT);
234 len = min_t(u8, len, 32);
235 case I2C_SMBUS_I2C_BLOCK_DATA:
236 for (i = 0; i < len; i++)
237 data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
238 data->block[0] = len;
239 break;
240 }
241
242 return 0;
243}
244
245
246static u32 nforce2_func(struct i2c_adapter *adapter)
247{
248 /* other functionality might be possible, but is not tested */
249 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
250 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA /* |
251 I2C_FUNC_SMBUS_BLOCK_DATA */;
252}
253
254
255static struct pci_device_id nforce2_ids[] = {
256 { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
257 { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
258 { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
259 { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
260 { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
Jean Delvare7c72ccf2005-12-18 17:25:18 +0100261 { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS) },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 { 0 }
263};
264
265
266MODULE_DEVICE_TABLE (pci, nforce2_ids);
267
268
269static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg,
270 struct nforce2_smbus *smbus, char *name)
271{
272 u16 iobase;
273 int error;
274
275 if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) {
276 dev_err(&smbus->adapter.dev, "Error reading PCI config for %s\n", name);
277 return -1;
278 }
279 smbus->dev = dev;
280 smbus->base = iobase & 0xfffc;
281 smbus->size = 8;
282
Jean Delvared6072f82005-09-25 16:37:04 +0200283 if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
285 smbus->base, smbus->base+smbus->size-1, name);
286 return -1;
287 }
288 smbus->adapter = nforce2_adapter;
289 smbus->adapter.algo_data = smbus;
290 smbus->adapter.dev.parent = &dev->dev;
291 snprintf(smbus->adapter.name, I2C_NAME_SIZE,
292 "SMBus nForce2 adapter at %04x", smbus->base);
293
294 error = i2c_add_adapter(&smbus->adapter);
295 if (error) {
296 dev_err(&smbus->adapter.dev, "Failed to register adapter.\n");
297 release_region(smbus->base, smbus->size);
298 return -1;
299 }
300 dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base);
301 return 0;
302}
303
304
305static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
306{
307 struct nforce2_smbus *smbuses;
308 int res1, res2;
309
310 /* we support 2 SMBus adapters */
Jean Delvare078d9fe2005-10-17 23:12:36 +0200311 if (!(smbuses = kzalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 pci_set_drvdata(dev, smbuses);
314
315 /* SMBus adapter 1 */
316 res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
317 if (res1 < 0) {
318 dev_err(&dev->dev, "Error probing SMB1.\n");
319 smbuses[0].base = 0; /* to have a check value */
320 }
321 res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
322 if (res2 < 0) {
323 dev_err(&dev->dev, "Error probing SMB2.\n");
324 smbuses[1].base = 0; /* to have a check value */
325 }
326 if ((res1 < 0) && (res2 < 0)) {
327 /* we did not find even one of the SMBuses, so we give up */
328 kfree(smbuses);
329 return -ENODEV;
330 }
331
332 return 0;
333}
334
335
336static void __devexit nforce2_remove(struct pci_dev *dev)
337{
338 struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev);
339
340 if (smbuses[0].base) {
341 i2c_del_adapter(&smbuses[0].adapter);
342 release_region(smbuses[0].base, smbuses[0].size);
343 }
344 if (smbuses[1].base) {
345 i2c_del_adapter(&smbuses[1].adapter);
346 release_region(smbuses[1].base, smbuses[1].size);
347 }
348 kfree(smbuses);
349}
350
351static struct pci_driver nforce2_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 .name = "nForce2_smbus",
353 .id_table = nforce2_ids,
354 .probe = nforce2_probe,
355 .remove = __devexit_p(nforce2_remove),
356};
357
358static int __init nforce2_init(void)
359{
360 return pci_register_driver(&nforce2_driver);
361}
362
363static void __exit nforce2_exit(void)
364{
365 pci_unregister_driver(&nforce2_driver);
366}
367
368module_init(nforce2_init);
369module_exit(nforce2_exit);
370