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

Revision 3072, 11.4 KB (checked in by khali, 9 years ago)

Remove dead code. Backport from a 2.6 kernel patch by
Hans-Frieder Vogt.

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