root/lm-sensors/trunk/kernel/busses/i2c-viapro.c @ 1708

Revision 1708, 13.0 KB (checked in by kmalkki, 10 years ago)

(Kyösti) Clean PCI IDs already defined for 2.4.9.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    i2c-viapro.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4    Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
5    Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
6    Mark D. Studebaker <mdsxyz123@yahoo.com>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/*
24   Supports Via devices:
25        82C596A/B (0x3050)
26        82C596B (0x3051)
27        82C686A/B
28        8231
29        8233
30        8233A (0x3147 and 0x3177)
31        8235
32   Note: we assume there can only be one device, with one SMBus interface.
33*/
34
35#include <linux/module.h>
36#include <linux/pci.h>
37#include <linux/kernel.h>
38#include <linux/stddef.h>
39#include <linux/sched.h>
40#include <linux/ioport.h>
41#include <linux/i2c.h>
42#include <linux/init.h>
43#include <asm/io.h>
44#include "version.h"
45
46#define SMBBA1      0x90
47#define SMBBA2      0x80
48#define SMBBA3      0xD0
49
50struct sd {
51        const unsigned short dev;
52        const unsigned char base;
53        const unsigned char hstcfg;
54        const char *name;
55};
56
57static struct sd supported[] = {
58        {PCI_DEVICE_ID_VIA_82C596_3, SMBBA1, 0xD2, "VT82C596A/B"},
59        {PCI_DEVICE_ID_VIA_82C596B_3, SMBBA1, 0xD2, "VT82C596B"},
60        {PCI_DEVICE_ID_VIA_82C686_4, SMBBA1, 0xD2, "VT82C686A/B"},
61        {PCI_DEVICE_ID_VIA_8233_0, SMBBA3, 0xD2, "VT8233"},
62        {0x3147, SMBBA3, 0xD2, "VT8233A"},
63        {0x3177, SMBBA3, 0xD2, "VT8233A/8235"},
64        {0x8235, SMBBA1, 0xD2, "VT8231"},
65        {0, 0, 0, NULL}
66};
67
68static struct sd *num = supported;
69
70/* SMBus address offsets */
71#define SMBHSTSTS (0 + vt596_smba)
72#define SMBHSLVSTS (1 + vt596_smba)
73#define SMBHSTCNT (2 + vt596_smba)
74#define SMBHSTCMD (3 + vt596_smba)
75#define SMBHSTADD (4 + vt596_smba)
76#define SMBHSTDAT0 (5 + vt596_smba)
77#define SMBHSTDAT1 (6 + vt596_smba)
78#define SMBBLKDAT (7 + vt596_smba)
79#define SMBSLVCNT (8 + vt596_smba)
80#define SMBSHDWCMD (9 + vt596_smba)
81#define SMBSLVEVT (0xA + vt596_smba)
82#define SMBSLVDAT (0xC + vt596_smba)
83
84/* PCI Address Constants */
85
86/* SMBus data in configuration space can be found in two places,
87   We try to select the better one*/
88
89static unsigned short smb_cf_hstcfg;
90
91#define SMBHSTCFG   (smb_cf_hstcfg)
92#define SMBSLVC     (SMBHSTCFG+1)
93#define SMBSHDW1    (SMBHSTCFG+2)
94#define SMBSHDW2    (SMBHSTCFG+3)
95#define SMBREV      (SMBHSTCFG+4)
96
97/* Other settings */
98#define MAX_TIMEOUT 500
99#define  ENABLE_INT9 0
100
101/* VT82C596 constants */
102#define VT596_QUICK      0x00
103#define VT596_BYTE       0x04
104#define VT596_BYTE_DATA  0x08
105#define VT596_WORD_DATA  0x0C
106#define VT596_BLOCK_DATA 0x14
107
108/* insmod parameters */
109
110/* If force is set to anything different from 0, we forcibly enable the
111   VT596. DANGEROUS! */
112static int force = 0;
113MODULE_PARM(force, "i");
114MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
115
116/* If force_addr is set to anything different from 0, we forcibly enable
117   the VT596 at the given address. VERY DANGEROUS! */
118static int force_addr = 0;
119MODULE_PARM(force_addr, "i");
120MODULE_PARM_DESC(force_addr,
121                 "Forcibly enable the SMBus at the given address. "
122                 "EXTREMELY DANGEROUS!");
123
124
125
126
127
128static void vt596_do_pause(unsigned int amount);
129static int vt596_transaction(void);
130
131
132
133static unsigned short vt596_smba = 0;
134
135
136/* Detect whether a compatible device can be found, and initialize it. */
137int vt596_setup(void)
138{
139        unsigned char temp;
140
141        struct pci_dev *VT596_dev = NULL;
142
143        /* First check whether we can access PCI at all */
144        if (pci_present() == 0)
145                return(-ENODEV);
146
147        /* Look for a supported device/function */
148        do {
149                if((VT596_dev = pci_find_device(PCI_VENDOR_ID_VIA, num->dev,
150                                                VT596_dev)))
151                        break;
152        } while ((++num)->dev);
153
154        if (VT596_dev == NULL)
155                return(-ENODEV);
156        printk("i2c-viapro.o: Found Via %s device\n", num->name);
157
158/* Determine the address of the SMBus areas */
159        smb_cf_hstcfg = num->hstcfg;
160        if (force_addr) {
161                vt596_smba = force_addr & 0xfff0;
162                force = 0;
163        } else {
164                if ((pci_read_config_word(VT596_dev, num->base, &vt596_smba))
165                    || !(vt596_smba & 0x1)) {
166                        /* try 2nd address and config reg. for 596 */
167                        if((num->dev == PCI_DEVICE_ID_VIA_82C596_3) &&
168                           (!pci_read_config_word(VT596_dev, SMBBA2, &vt596_smba)) &&
169                           (vt596_smba & 0x1)) {
170                                smb_cf_hstcfg = 0x84;
171                        } else {
172                                /* no matches at all */
173                                printk("i2c-viapro.o: Cannot configure SMBus "
174                                       "I/O Base address\n");
175                                return(-ENODEV);
176                        }
177                }
178                vt596_smba &= 0xfff0;
179                if(vt596_smba == 0) {
180                        printk(KERN_ERR "i2c-viapro.o: SMBus base address"
181                           "uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
182                        return -ENODEV;
183                }
184        }
185
186        if (check_region(vt596_smba, 8)) {
187                printk("i2c-viapro.o: SMBus region 0x%x already in use!\n",
188                        vt596_smba);
189                return(-ENODEV);
190        }
191
192        pci_read_config_byte(VT596_dev, SMBHSTCFG, &temp);
193/* If force_addr is set, we program the new address here. Just to make
194   sure, we disable the VT596 first. */
195        if (force_addr) {
196                pci_write_config_byte(VT596_dev, SMBHSTCFG, temp & 0xfe);
197                pci_write_config_word(VT596_dev, num->base, vt596_smba);
198                pci_write_config_byte(VT596_dev, SMBHSTCFG, temp | 0x01);
199                printk
200                    ("i2c-viapro.o: WARNING: SMBus interface set to new "
201                     "address 0x%04x!\n", vt596_smba);
202        } else if ((temp & 1) == 0) {
203                if (force) {
204/* NOTE: This assumes I/O space and other allocations WERE
205   done by the Bios!  Don't complain if your hardware does weird
206   things after enabling this. :') Check for Bios updates before
207   resorting to this.  */
208                        pci_write_config_byte(VT596_dev, SMBHSTCFG,
209                                              temp | 1);
210                        printk
211                            ("i2c-viapro.o: enabling SMBus device\n");
212                } else {
213                        printk
214                            ("SMBUS: Error: Host SMBus controller not enabled! - "
215                             "upgrade BIOS or use force=1\n");
216                        return(-ENODEV);
217                }
218        }
219
220        /* Everything is happy, let's grab the memory and set things up. */
221        request_region(vt596_smba, 8, "viapro-smbus");
222
223#ifdef DEBUG
224        if ((temp & 0x0E) == 8)
225                printk("i2c-viapro.o: using Interrupt 9 for SMBus.\n");
226        else if ((temp & 0x0E) == 0)
227                printk("i2c-viapro.o: using Interrupt SMI# for SMBus.\n");
228        else
229                printk
230                    ("i2c-viapro.o: Illegal Interrupt configuration (or code out "
231                     "of date)!\n");
232
233        pci_read_config_byte(VT596_dev, SMBREV, &temp);
234        printk("i2c-viapro.o: SMBREV = 0x%X\n", temp);
235        printk("i2c-viapro.o: VT596_smba = 0x%X\n", vt596_smba);
236#endif                          /* DEBUG */
237
238        return(0);
239}
240
241
242/* Internally used pause function */
243void vt596_do_pause(unsigned int amount)
244{
245        current->state = TASK_INTERRUPTIBLE;
246        schedule_timeout(amount);
247}
248
249/* Another internally used function */
250int vt596_transaction(void)
251{
252        int temp;
253        int result = 0;
254        int timeout = 0;
255
256#ifdef DEBUG
257        printk
258            ("i2c-viapro.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
259             "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
260             inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
261#endif
262
263        /* Make sure the SMBus host is ready to start transmitting */
264        if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
265#ifdef DEBUG
266                printk("i2c-viapro.o: SMBus busy (0x%02x). Resetting... \n",
267                       temp);
268#endif
269                outb_p(temp, SMBHSTSTS);
270                if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
271#ifdef DEBUG
272                        printk("i2c-viapro.o: Failed! (0x%02x)\n", temp);
273#endif
274                        return -1;
275                } else {
276#ifdef DEBUG
277                        printk("i2c-viapro.o: Successfull!\n");
278#endif
279                }
280        }
281
282        /* start the transaction by setting bit 6 */
283        outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
284
285        /* We will always wait for a fraction of a second!
286           I don't know if VIA needs this, Intel did  */
287        do {
288                vt596_do_pause(1);
289                temp = inb_p(SMBHSTSTS);
290        } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
291
292        /* If the SMBus is still busy, we give up */
293        if (timeout >= MAX_TIMEOUT) {
294#ifdef DEBUG
295                printk("i2c-viapro.o: SMBus Timeout!\n");
296                result = -1;
297#endif
298        }
299
300        if (temp & 0x10) {
301                result = -1;
302#ifdef DEBUG
303                printk("i2c-viapro.o: Error: Failed bus transaction\n");
304#endif
305        }
306
307        if (temp & 0x08) {
308                result = -1;
309                printk
310                    ("i2c-viapro.o: Bus collision! SMBus may be locked until next hard\n"
311                     "reset. (sorry!)\n");
312                /* Clock stops and slave is stuck in mid-transmission */
313        }
314
315        if (temp & 0x04) {
316                result = -1;
317#ifdef DEBUG
318                printk("i2c-viapro.o: Error: no response!\n");
319#endif
320        }
321
322        if (inb_p(SMBHSTSTS) != 0x00)
323                outb_p(inb(SMBHSTSTS), SMBHSTSTS);
324
325        if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
326#ifdef DEBUG
327                printk
328                    ("i2c-viapro.o: Failed reset at end of transaction (%02x)\n",
329                     temp);
330#endif
331        }
332#ifdef DEBUG
333        printk
334            ("i2c-viapro.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
335             "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
336             inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
337#endif
338        return result;
339}
340
341/* Return -1 on error. */
342s32 vt596_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
343                 char read_write,
344                 u8 command, int size, union i2c_smbus_data * data)
345{
346        int i, len;
347
348        switch (size) {
349        case I2C_SMBUS_PROC_CALL:
350                printk
351                    ("i2c-viapro.o: I2C_SMBUS_PROC_CALL not supported!\n");
352                return -1;
353        case I2C_SMBUS_QUICK:
354                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
355                       SMBHSTADD);
356                size = VT596_QUICK;
357                break;
358        case I2C_SMBUS_BYTE:
359                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
360                       SMBHSTADD);
361                if (read_write == I2C_SMBUS_WRITE)
362                        outb_p(command, SMBHSTCMD);
363                size = VT596_BYTE;
364                break;
365        case I2C_SMBUS_BYTE_DATA:
366                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
367                       SMBHSTADD);
368                outb_p(command, SMBHSTCMD);
369                if (read_write == I2C_SMBUS_WRITE)
370                        outb_p(data->byte, SMBHSTDAT0);
371                size = VT596_BYTE_DATA;
372                break;
373        case I2C_SMBUS_WORD_DATA:
374                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
375                       SMBHSTADD);
376                outb_p(command, SMBHSTCMD);
377                if (read_write == I2C_SMBUS_WRITE) {
378                        outb_p(data->word & 0xff, SMBHSTDAT0);
379                        outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
380                }
381                size = VT596_WORD_DATA;
382                break;
383        case I2C_SMBUS_BLOCK_DATA:
384                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
385                       SMBHSTADD);
386                outb_p(command, SMBHSTCMD);
387                if (read_write == I2C_SMBUS_WRITE) {
388                        len = data->block[0];
389                        if (len < 0)
390                                len = 0;
391                        if (len > 32)
392                                len = 32;
393                        outb_p(len, SMBHSTDAT0);
394                        i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
395                        for (i = 1; i <= len; i++)
396                                outb_p(data->block[i], SMBBLKDAT);
397                }
398                size = VT596_BLOCK_DATA;
399                break;
400        }
401
402        outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
403
404        if (vt596_transaction())        /* Error in transaction */
405                return -1;
406
407        if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
408                return 0;
409
410
411        switch (size) {
412        case VT596_BYTE:        /* Where is the result put? I assume here it is in
413                                   SMBHSTDAT0 but it might just as well be in the
414                                   SMBHSTCMD. No clue in the docs */
415
416                data->byte = inb_p(SMBHSTDAT0);
417                break;
418        case VT596_BYTE_DATA:
419                data->byte = inb_p(SMBHSTDAT0);
420                break;
421        case VT596_WORD_DATA:
422                data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
423                break;
424        case VT596_BLOCK_DATA:
425                data->block[0] = inb_p(SMBHSTDAT0);
426                i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
427                for (i = 1; i <= data->block[0]; i++)
428                        data->block[i] = inb_p(SMBBLKDAT);
429                break;
430        }
431        return 0;
432}
433
434
435u32 vt596_func(struct i2c_adapter *adapter)
436{
437        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
438            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
439            I2C_FUNC_SMBUS_BLOCK_DATA;
440}
441
442
443static struct i2c_algorithm smbus_algorithm = {
444        .name           = "Non-I2C SMBus adapter",
445        .id             = I2C_ALGO_SMBUS,
446        .smbus_xfer     = vt596_access,
447        .functionality  = vt596_func,
448};
449
450static struct i2c_adapter vt596_adapter = {
451        .owner          = THIS_MODULE,
452        .name           = "unset",
453        .id             = I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2,
454        .algo           = &smbus_algorithm,
455};
456
457
458static struct pci_device_id vt596_ids[] __devinitdata = {
459        { 0, }
460};
461
462static int __devinit vt596_probe(struct pci_dev *dev, const struct pci_device_id *id)
463{
464
465        if (vt596_setup()) {
466                printk
467                    ("i2c-viapro.o: Can't detect vt82c596 or compatible device, module not inserted.\n");
468
469                return -ENODEV;
470        }
471
472        sprintf(vt596_adapter.name, "SMBus Via Pro adapter at %04x",
473                vt596_smba);
474        i2c_add_adapter(&vt596_adapter);
475}
476
477static void __devexit vt596_remove(struct pci_dev *dev)
478{
479        i2c_del_adapter(&vt596_adapter);
480}
481
482static struct pci_driver vt596_driver = {
483        .name           = "vt596 smbus",
484        .id_table       = vt596_ids,
485        .probe          = vt596_probe,
486        .remove         = __devexit_p(vt596_remove),
487};
488
489static int __init i2c_vt596_init(void)
490{
491        printk("i2c-viapro.o version %s (%s)\n", LM_VERSION, LM_DATE);
492        return pci_module_init(&vt596_driver);
493}
494
495
496static void __exit i2c_vt596_exit(void)
497{
498        pci_unregister_driver(&vt596_driver);
499        release_region(vt596_smba, 8);
500}
501
502
503
504MODULE_AUTHOR
505    ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
506MODULE_DESCRIPTION("vt82c596 SMBus driver");
507
508MODULE_LICENSE("GPL");
509
510module_init(i2c_vt596_init);
511module_exit(i2c_vt596_exit);
Note: See TracBrowser for help on using the browser.