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

Revision 2802, 12.0 KB (checked in by khali, 9 years ago)

Include sensors_compat.h for devexit_p (only exists since

kernel 2.4.17).

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