root/lm-sensors/trunk/kernel/busses/i2c-nforce2.c @ 4389

Revision 4389, 12.4 KB (checked in by khali, 6 years ago)

i2c-nforce2: Add support for the nForce MCP61 and MCP65. This is a
backport from Linux 2.6.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    SMBus driver for nVidia nForce2 MCP
3
4    Copyright (c) 2003  Hans-Frieder Vogt <hfvogt@arcor.de>,
5    Based on
6    SMBus 2.0 driver for AMD-8111 IO-Hub
7    Copyright (c) 2002 Vojtech Pavlik
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22*/
23
24/*
25    SUPPORTED DEVICES           PCI ID
26    nForce2 MCP                 0064
27    nForce2 Ultra 400 MCP       0084
28    nForce3 Pro150 MCP          00D4
29    nForce3 250Gb MCP           00E4
30    nForce4 MCP                 0052
31    nForce4 MCP-04              0034
32    nForce4 MCP51               0264
33    nForce4 MCP55               0368
34    nForce MCP61                03EB
35    nForce MCP65                0446
36
37    This driver supports the 2 SMBuses that are included in the MCP of the
38    nForce2/3/4 chipsets.
39*/
40
41/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
42
43#include <linux/module.h>
44#include <linux/pci.h>
45#include <linux/kernel.h>
46#include <linux/stddef.h>
47#include <linux/sched.h>
48#include <linux/ioport.h>
49#include <linux/init.h>
50#include <linux/i2c.h>
51#include <linux/delay.h>
52#include <linux/slab.h>
53#include <asm/io.h>
54#include "version.h"
55#include "sensors_compat.h"
56
57MODULE_LICENSE("GPL");
58MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
59MODULE_DESCRIPTION("nForce2 SMBus driver");
60
61#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS
62#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS      0x0064
63#endif
64
65#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS
66#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS     0x0084
67#endif
68
69#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS
70#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS      0x00D4
71#endif
72
73#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS
74#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS     0x00E4
75#endif
76
77#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS
78#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS      0x0052
79#endif
80
81#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034
82#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264
83#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368
84#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB
85#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446
86
87
88struct nforce2_smbus {
89        struct i2c_adapter adapter;
90        int base;
91        int size;
92};
93
94
95/*
96 * nVidia nForce2 SMBus control register definitions
97 * (Newer incarnations use standard BARs 4 and 5 instead)
98 */
99#define NFORCE_PCI_SMB1 0x50
100#define NFORCE_PCI_SMB2 0x54
101
102
103/*
104 * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
105 */
106#define NVIDIA_SMB_PRTCL        (smbus->base + 0x00)    /* protocol, PEC */
107#define NVIDIA_SMB_STS          (smbus->base + 0x01)    /* status */
108#define NVIDIA_SMB_ADDR         (smbus->base + 0x02)    /* address */
109#define NVIDIA_SMB_CMD          (smbus->base + 0x03)    /* command */
110#define NVIDIA_SMB_DATA         (smbus->base + 0x04)    /* 32 data registers */
111#define NVIDIA_SMB_BCNT         (smbus->base + 0x24)    /* number of data bytes */
112#define NVIDIA_SMB_ALRM_A       (smbus->base + 0x25)    /* alarm address */
113#define NVIDIA_SMB_ALRM_D       (smbus->base + 0x26)    /* 2 bytes alarm data */
114
115#define NVIDIA_SMB_STS_DONE     0x80
116#define NVIDIA_SMB_STS_ALRM     0x40
117#define NVIDIA_SMB_STS_RES      0x20
118#define NVIDIA_SMB_STS_STATUS   0x1f
119
120#define NVIDIA_SMB_PRTCL_WRITE                  0x00
121#define NVIDIA_SMB_PRTCL_READ                   0x01
122#define NVIDIA_SMB_PRTCL_QUICK                  0x02
123#define NVIDIA_SMB_PRTCL_BYTE                   0x04
124#define NVIDIA_SMB_PRTCL_BYTE_DATA              0x06
125#define NVIDIA_SMB_PRTCL_WORD_DATA              0x08
126#define NVIDIA_SMB_PRTCL_BLOCK_DATA             0x0a
127#define NVIDIA_SMB_PRTCL_PROC_CALL              0x0c
128#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL        0x0d
129#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA         0x4a
130#define NVIDIA_SMB_PRTCL_PEC                    0x80
131
132static struct pci_driver nforce2_driver;
133
134static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
135                       unsigned short flags, char read_write,
136                       u8 command, int size, union i2c_smbus_data *data);
137/*
138static int nforce2_block_transaction(union i2c_smbus_data *data,
139                                  char read_write, int i2c_enable);
140 */
141static u32 nforce2_func(struct i2c_adapter *adapter);
142
143
144static struct i2c_algorithm smbus_algorithm = {
145        .name = "Non-I2C SMBus adapter",
146        .id = I2C_ALGO_SMBUS,
147        .smbus_xfer = nforce2_access,
148        .functionality = nforce2_func,
149};
150
151/* Return -1 on error. See smbus.h for more information */
152s32 nforce2_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
153                char read_write, u8 command, int size,
154                union i2c_smbus_data * data)
155{
156        struct nforce2_smbus *smbus = adap->algo_data;
157        unsigned char protocol, pec, temp;
158        unsigned char len = 0; /* to keep the compiler quiet */
159        int i;
160
161        protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ : NVIDIA_SMB_PRTCL_WRITE;
162        pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
163
164        switch (size) {
165
166                case I2C_SMBUS_QUICK:
167                        protocol |= NVIDIA_SMB_PRTCL_QUICK;
168                        read_write = I2C_SMBUS_WRITE;
169                        break;
170
171                case I2C_SMBUS_BYTE:
172                        if (read_write == I2C_SMBUS_WRITE)
173                                outb_p(command, NVIDIA_SMB_CMD);
174                        protocol |= NVIDIA_SMB_PRTCL_BYTE;
175                        break;
176
177                case I2C_SMBUS_BYTE_DATA:
178                        outb_p(command, NVIDIA_SMB_CMD);
179                        if (read_write == I2C_SMBUS_WRITE)
180                                outb_p(data->byte, NVIDIA_SMB_DATA);
181                        protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
182                        break;
183
184                case I2C_SMBUS_WORD_DATA:
185                        outb_p(command, NVIDIA_SMB_CMD);
186                        if (read_write == I2C_SMBUS_WRITE) {
187                                 outb_p(data->word, NVIDIA_SMB_DATA);
188                                 outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);
189                        }
190                        protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
191                        break;
192
193                case I2C_SMBUS_BLOCK_DATA:
194                        outb_p(command, NVIDIA_SMB_CMD);
195                        if (read_write == I2C_SMBUS_WRITE) {
196                                len = min_t(u8, data->block[0], 32);
197                                outb_p(len, NVIDIA_SMB_BCNT);
198                                for (i = 0; i < len; i++)
199                                        outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
200                        }
201                        protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
202                        break;
203
204                case I2C_SMBUS_I2C_BLOCK_DATA:
205                        len = min_t(u8, data->block[0], 32);
206                        outb_p(command, NVIDIA_SMB_CMD);
207                        outb_p(len, NVIDIA_SMB_BCNT);
208                        if (read_write == I2C_SMBUS_WRITE)
209                                for (i = 0; i < len; i++)
210                                        outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
211                        protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
212                        break;
213
214                case I2C_SMBUS_PROC_CALL:
215                        printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_PROC_CALL not supported!\n");
216                        return -1;
217
218                case I2C_SMBUS_BLOCK_PROC_CALL:
219                        printk(KERN_WARNING "i2c-nforce2.o: I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
220                        return -1;
221
222                default:
223                        printk(KERN_WARNING "i2c-nforce2.c: Unsupported transaction %d\n", size);
224                        return -1;
225        }
226
227        outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
228        outb_p(protocol, NVIDIA_SMB_PRTCL);
229
230        temp = inb_p(NVIDIA_SMB_STS);
231
232        if (~temp & NVIDIA_SMB_STS_DONE) {
233                udelay(500);
234                temp = inb_p(NVIDIA_SMB_STS);
235        }
236        if (~temp & NVIDIA_SMB_STS_DONE) {
237                i2c_delay(HZ/100);
238                temp = inb_p(NVIDIA_SMB_STS);
239        }
240
241        if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) {
242                printk(KERN_DEBUG "i2c-nforce2.o: SMBus Timeout! (0x%02x)\n",
243                       temp);
244                return -1;
245        }
246
247        if (read_write == I2C_SMBUS_WRITE)
248                return 0;
249
250        switch (size) {
251
252                case I2C_SMBUS_BYTE:
253                case I2C_SMBUS_BYTE_DATA:
254                        data->byte = inb_p(NVIDIA_SMB_DATA);
255                        break;
256
257                case I2C_SMBUS_WORD_DATA:
258                /* case I2C_SMBUS_PROC_CALL: not supported */
259                        data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
260                        break;
261
262                case I2C_SMBUS_BLOCK_DATA:
263                /* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
264                        len = inb_p(NVIDIA_SMB_BCNT);
265                        len = min_t(u8, len, 32);
266                case I2C_SMBUS_I2C_BLOCK_DATA:
267                        for (i = 0; i < len; i++)
268                                data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
269                        data->block[0] = len;
270                        break;
271        }
272
273        return 0;
274}
275
276
277u32 nforce2_func(struct i2c_adapter *adapter)
278{
279        /* other functionality might be possible, but is not tested */
280        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
281            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA /* |
282            I2C_FUNC_SMBUS_BLOCK_DATA */;
283}
284
285static void nforce2_inc(struct i2c_adapter *adapter)
286{
287#ifdef MODULE
288        MOD_INC_USE_COUNT;
289#endif
290}
291
292static void nforce2_dec(struct i2c_adapter *adapter)
293{
294#ifdef MODULE
295        MOD_DEC_USE_COUNT;
296#endif
297}
298
299static struct pci_device_id nforce2_ids[] = {
300        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS,
301                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
302        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS,
303                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
304        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS,
305                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
306        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS,
307                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
308        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS,
309                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
310        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS,
311                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
312        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
313                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
314        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
315                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
316        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS,
317                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
318        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS,
319                PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
320        { 0 }
321};
322
323
324static int __devinit nforce2_probe_smb(struct pci_dev *dev, int bar,
325        int alt_reg, struct nforce2_smbus *smbus, char *name)
326{
327        int error;
328
329        smbus->base = pci_resource_start(dev, bar);
330        if (smbus->base) {
331                smbus->size = pci_resource_len(dev, bar);
332        } else {
333                /* Older incarnations of the device used non-standard BARs */
334                u16 iobase;
335
336                if (pci_read_config_word(dev, alt_reg, &iobase)
337                    != PCIBIOS_SUCCESSFUL) {
338                        printk(KERN_ERR "i2c-nforce2.o: Error reading PCI "
339                               "config for %s\n", name);
340                        return -1;
341                }
342
343                smbus->base = iobase & PCI_BASE_ADDRESS_IO_MASK;
344                smbus->size = 8;
345        }
346
347        if (!request_region(smbus->base, smbus->size, nforce2_driver.name)) {
348                printk (KERN_ERR "i2c-nforce2.o: Error requesting region %02x .. %02X for %s\n", smbus->base, smbus->base+smbus->size-1, name);
349                return -1;
350        }
351
352        sprintf(smbus->adapter.name, "SMBus nForce2 adapter at %04x", smbus->base);
353        smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_NFORCE2;
354        smbus->adapter.algo = &smbus_algorithm;
355        smbus->adapter.algo_data = smbus;
356        smbus->adapter.inc_use = nforce2_inc;
357        smbus->adapter.dec_use = nforce2_dec;
358
359        error = i2c_add_adapter(&smbus->adapter);
360        if (error) {
361                printk(KERN_WARNING "i2c-nforce2.o: Failed to register adapter.\n");
362                release_region(smbus->base, smbus->size);
363                return -1;
364        }
365        printk(KERN_INFO "i2c-nforce2.o: nForce2 SMBus adapter at %#x\n", smbus->base);
366        return 0;
367}
368
369
370static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
371{
372        struct nforce2_smbus *smbuses;
373        int res1, res2;
374
375        /* we support 2 SMBus adapters */
376        if (!(smbuses = kmalloc(2*sizeof(struct nforce2_smbus), GFP_KERNEL)))
377                return -ENOMEM;
378        memset (smbuses, 0, 2*sizeof(struct nforce2_smbus));
379        pci_set_drvdata(dev, smbuses);
380
381        /* SMBus adapter 1 */
382        res1 = nforce2_probe_smb(dev, 4, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
383        if (res1 < 0) {
384                printk (KERN_ERR "i2c-nforce2.o: Error probing SMB1.\n");
385                smbuses[0].base = 0;    /* to have a check value */
386        }
387        /* SMBus adapter 2 */
388        res2 = nforce2_probe_smb(dev, 5, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
389        if (res2 < 0) {
390                printk (KERN_ERR "i2c-nforce2.o: Error probing SMB2.\n");
391                smbuses[1].base = 0;    /* to have a check value */
392        }
393        if ((res1 < 0) && (res2 < 0)) {
394                /* we did not find even one of the SMBuses, so we give up */
395                kfree(smbuses);
396                return -ENODEV;
397        }
398
399        return 0;
400}
401
402
403static void __devexit nforce2_remove(struct pci_dev *dev)
404{
405        struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev);
406
407        if (smbuses[0].base) {
408                i2c_del_adapter(&smbuses[0].adapter);
409                release_region(smbuses[0].base, smbuses[0].size);
410        }
411        if (smbuses[1].base) {
412                i2c_del_adapter(&smbuses[1].adapter);
413                release_region(smbuses[1].base, smbuses[1].size);
414        }
415        kfree(smbuses);
416}
417
418static struct pci_driver nforce2_driver = {
419        .name           = "nForce2 SMBus",
420        .id_table       = nforce2_ids,
421        .probe          = nforce2_probe,
422        .remove         = __devexit_p(nforce2_remove),
423};
424
425int __init nforce2_init(void)
426{
427        printk(KERN_INFO "i2c-nforce2.o version %s (%s)\n", LM_VERSION, LM_DATE);
428        return pci_module_init(&nforce2_driver);
429}
430
431void __exit nforce2_exit(void)
432{
433        pci_unregister_driver(&nforce2_driver);
434}
435
436module_init(nforce2_init);
437module_exit(nforce2_exit);
438
Note: See TracBrowser for help on using the browser.