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

Revision 1708, 13.7 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    piix4.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4    Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
5    Philip Edelbrock <phil@netroedge.com>
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22/*
23   Supports:
24        Intel PIIX4, 440MX
25        Serverworks OSB4, CSB5
26        SMSC Victory66
27
28   Note: we assume there can only be one device, with one SMBus interface.
29*/
30
31#include <linux/version.h>
32#include <linux/module.h>
33#include <linux/config.h>
34#include <linux/pci.h>
35#include <linux/kernel.h>
36#include <linux/stddef.h>
37#include <linux/sched.h>
38#include <linux/ioport.h>
39#include <linux/i2c.h>
40#include <linux/init.h>
41#include <linux/apm_bios.h>
42#include <asm/io.h>
43#include "version.h"
44#include "dmi_scan.h"
45
46
47struct sd {
48        const unsigned short mfr;
49        const unsigned short dev;
50        const unsigned char fn;
51        const char *name;
52};
53
54/* Note: We assume all devices are identical
55         to the Intel PIIX4; we only mention it during detection.   */
56
57static struct sd supported[] = {
58        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, 3, "PIIX4"},
59        {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4, 0, "OSB4"},
60        {PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5, 0, "CSB5"},
61        {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3, 3, "440MX"},
62        {PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3, 0, "Victory66"},
63        {0, 0, 0, NULL}
64};
65
66/* PIIX4 SMBus address offsets */
67#define SMBHSTSTS (0 + piix4_smba)
68#define SMBHSLVSTS (1 + piix4_smba)
69#define SMBHSTCNT (2 + piix4_smba)
70#define SMBHSTCMD (3 + piix4_smba)
71#define SMBHSTADD (4 + piix4_smba)
72#define SMBHSTDAT0 (5 + piix4_smba)
73#define SMBHSTDAT1 (6 + piix4_smba)
74#define SMBBLKDAT (7 + piix4_smba)
75#define SMBSLVCNT (8 + piix4_smba)
76#define SMBSHDWCMD (9 + piix4_smba)
77#define SMBSLVEVT (0xA + piix4_smba)
78#define SMBSLVDAT (0xC + piix4_smba)
79
80/* PCI Address Constants */
81#define SMBBA     0x090
82#define SMBHSTCFG 0x0D2
83#define SMBSLVC   0x0D3
84#define SMBSHDW1  0x0D4
85#define SMBSHDW2  0x0D5
86#define SMBREV    0x0D6
87
88/* Other settings */
89#define MAX_TIMEOUT 500
90#define  ENABLE_INT9 0
91
92/* PIIX4 constants */
93#define PIIX4_QUICK      0x00
94#define PIIX4_BYTE       0x04
95#define PIIX4_BYTE_DATA  0x08
96#define PIIX4_WORD_DATA  0x0C
97#define PIIX4_BLOCK_DATA 0x14
98
99/* insmod parameters */
100
101/* If force is set to anything different from 0, we forcibly enable the
102   PIIX4. DANGEROUS! */
103static int force = 0;
104MODULE_PARM(force, "i");
105MODULE_PARM_DESC(force, "Forcibly enable the PIIX4. DANGEROUS!");
106
107/* If force_addr is set to anything different from 0, we forcibly enable
108   the PIIX4 at the given address. VERY DANGEROUS! */
109static int force_addr = 0;
110MODULE_PARM(force_addr, "i");
111MODULE_PARM_DESC(force_addr,
112                 "Forcibly enable the PIIX4 at the given address. "
113                 "EXTREMELY DANGEROUS!");
114
115static void piix4_do_pause(unsigned int amount);
116static int piix4_transaction(void);
117
118
119static unsigned short piix4_smba = 0;
120
121#ifdef CONFIG_X86
122/*
123 * Get DMI information.
124 */
125#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,34)
126void dmi_scan_mach(void);
127#endif
128
129static int __init ibm_dmi_probe(void)
130{
131#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
132        extern int is_unsafe_smbus;
133        return is_unsafe_smbus;
134#else
135#define IBM_SIGNATURE           "IBM"
136        dmi_scan_mach();
137        if(dmi_ident[DMI_SYS_VENDOR] == NULL)
138                return 0;
139        if(strncmp(dmi_ident[DMI_SYS_VENDOR], IBM_SIGNATURE,
140                   strlen(IBM_SIGNATURE)) == 0)
141                return 1;
142        return 0;
143#endif
144}
145#endif
146
147/* Detect whether a PIIX4 can be found, and initialize it, where necessary.
148   Note the differences between kernels with the old PCI BIOS interface and
149   newer kernels with the real PCI interface. In compat.h some things are
150   defined to make the transition easier. */
151int piix4_setup(void)
152{
153        int error_return = 0;
154        unsigned char temp;
155        struct sd *num = supported;
156        struct pci_dev *PIIX4_dev = NULL;
157
158        if (pci_present() == 0) {
159                error_return = -ENODEV;
160                goto END;
161        }
162
163        /* Look for a supported device/function */
164        do {
165                if((PIIX4_dev = pci_find_device(num->mfr, num->dev,
166                                                PIIX4_dev))) {
167                        if(PCI_FUNC(PIIX4_dev->devfn) != num->fn)
168                                continue;
169                        break;
170                }
171                PIIX4_dev = NULL;
172                num++;
173        } while (num->mfr);
174
175        if (PIIX4_dev == NULL) {
176                printk
177                  (KERN_ERR "i2c-piix4.o: Error: Can't detect PIIX4 or compatible device!\n");
178                 error_return = -ENODEV;
179                 goto END;
180        }
181        printk(KERN_INFO "i2c-piix4.o: Found %s device\n", num->name);
182
183#ifdef CONFIG_X86
184        if(ibm_dmi_probe()) {
185                printk
186                  (KERN_ERR "i2c-piix4.o: IBM Laptop detected; this module may corrupt\n");
187                printk
188                  (KERN_ERR "             your serial eeprom! Refusing to load module!\n");
189                 error_return = -EPERM;
190                 goto END;
191        }
192#endif
193
194/* Determine the address of the SMBus areas */
195        if (force_addr) {
196                piix4_smba = force_addr & 0xfff0;
197                force = 0;
198        } else {
199                pci_read_config_word(PIIX4_dev, SMBBA, &piix4_smba);
200                piix4_smba &= 0xfff0;
201                if(piix4_smba == 0) {
202                        printk(KERN_ERR "i2c-piix4.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
203                        return -ENODEV;
204                }
205        }
206
207        if (check_region(piix4_smba, 8)) {
208                printk
209                    (KERN_ERR "i2c-piix4.o: SMB region 0x%x already in use!\n",
210                     piix4_smba);
211                error_return = -ENODEV;
212                goto END;
213        }
214
215        pci_read_config_byte(PIIX4_dev, SMBHSTCFG, &temp);
216/* If force_addr is set, we program the new address here. Just to make
217   sure, we disable the PIIX4 first. */
218        if (force_addr) {
219                pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp & 0xfe);
220                pci_write_config_word(PIIX4_dev, SMBBA, piix4_smba);
221                pci_write_config_byte(PIIX4_dev, SMBHSTCFG, temp | 0x01);
222                printk
223                    (KERN_INFO "i2c-piix4.o: WARNING: SMBus interface set to new "
224                     "address %04x!\n", piix4_smba);
225        } else if ((temp & 1) == 0) {
226                if (force) {
227/* This should never need to be done, but has been noted that
228   many Dell machines have the SMBus interface on the PIIX4
229   disabled!? NOTE: This assumes I/O space and other allocations WERE
230   done by the Bios!  Don't complain if your hardware does weird
231   things after enabling this. :') Check for Bios updates before
232   resorting to this.  */
233                        pci_write_config_byte(PIIX4_dev, SMBHSTCFG,
234                                              temp | 1);
235                        printk
236                            (KERN_NOTICE "i2c-piix4.o: WARNING: SMBus interface has been FORCEFULLY "
237                             "ENABLED!\n");
238                } else {
239                        printk
240                            (KERN_ERR "i2c-piix4.o: Host SMBus controller not enabled!\n");
241                        error_return = -ENODEV;
242                        goto END;
243                }
244        }
245
246        /* Everything is happy, let's grab the memory and set things up. */
247        request_region(piix4_smba, 8, "piix4-smbus");
248
249#ifdef DEBUG
250        if ((temp & 0x0E) == 8)
251                printk
252                    (KERN_DEBUG "i2c-piix4.o: Using Interrupt 9 for SMBus.\n");
253        else if ((temp & 0x0E) == 0)
254                printk
255                    (KERN_DEBUG "i2c-piix4.o: Using Interrupt SMI# for SMBus.\n");
256        else
257                printk
258                    (KERN_ERR "i2c-piix4.o: Illegal Interrupt configuration (or code out "
259                     "of date)!\n");
260
261        pci_read_config_byte(PIIX4_dev, SMBREV, &temp);
262        printk(KERN_DEBUG "i2c-piix4.o: SMBREV = 0x%X\n", temp);
263        printk(KERN_DEBUG "i2c-piix4.o: SMBA = 0x%X\n", piix4_smba);
264#endif                          /* DEBUG */
265
266      END:
267        return error_return;
268}
269
270
271/* Internally used pause function */
272void piix4_do_pause(unsigned int amount)
273{
274        current->state = TASK_INTERRUPTIBLE;
275        schedule_timeout(amount);
276}
277
278/* Another internally used function */
279int piix4_transaction(void)
280{
281        int temp;
282        int result = 0;
283        int timeout = 0;
284
285#ifdef DEBUG
286        printk
287            (KERN_DEBUG "i2c-piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
288             "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
289             inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
290#endif
291
292        /* Make sure the SMBus host is ready to start transmitting */
293        if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
294#ifdef DEBUG
295                printk(KERN_DEBUG "i2c-piix4.o: SMBus busy (%02x). Resetting... \n",
296                       temp);
297#endif
298                outb_p(temp, SMBHSTSTS);
299                if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
300#ifdef DEBUG
301                        printk(KERN_ERR "i2c-piix4.o: Failed! (%02x)\n", temp);
302#endif
303                        return -1;
304                } else {
305#ifdef DEBUG
306                        printk(KERN_DEBUG "i2c-piix4.o: Successfull!\n");
307#endif
308                }
309        }
310
311        /* start the transaction by setting bit 6 */
312        outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
313
314        /* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
315        do {
316                piix4_do_pause(1);
317                temp = inb_p(SMBHSTSTS);
318        } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
319
320#ifdef DEBUG
321        /* If the SMBus is still busy, we give up */
322        if (timeout >= MAX_TIMEOUT) {
323                printk(KERN_ERR "i2c-piix4.o: SMBus Timeout!\n");
324                result = -1;
325        }
326#endif
327
328        if (temp & 0x10) {
329                result = -1;
330#ifdef DEBUG
331                printk(KERN_ERR "i2c-piix4.o: Error: Failed bus transaction\n");
332#endif
333        }
334
335        if (temp & 0x08) {
336                result = -1;
337                printk
338                    (KERN_ERR "i2c-piix4.o: Bus collision! SMBus may be locked until next hard\n"
339                     "reset. (sorry!)\n");
340                /* Clock stops and slave is stuck in mid-transmission */
341        }
342
343        if (temp & 0x04) {
344                result = -1;
345#ifdef DEBUG
346                printk(KERN_ERR "i2c-piix4.o: Error: no response!\n");
347#endif
348        }
349
350        if (inb_p(SMBHSTSTS) != 0x00)
351                outb_p(inb(SMBHSTSTS), SMBHSTSTS);
352
353#ifdef DEBUG
354        if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
355                printk
356                    (KERN_ERR "i2c-piix4.o: Failed reset at end of transaction (%02x)\n",
357                     temp);
358        }
359        printk
360            (KERN_DEBUG "i2c-piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
361             "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
362             inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
363#endif
364        return result;
365}
366
367/* Return -1 on error. */
368s32 piix4_access(struct i2c_adapter * adap, u16 addr,
369                 unsigned short flags, char read_write,
370                 u8 command, int size, union i2c_smbus_data * data)
371{
372        int i, len;
373
374        switch (size) {
375        case I2C_SMBUS_PROC_CALL:
376                printk
377                    (KERN_ERR "i2c-piix4.o: I2C_SMBUS_PROC_CALL not supported!\n");
378                return -1;
379        case I2C_SMBUS_QUICK:
380                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
381                       SMBHSTADD);
382                size = PIIX4_QUICK;
383                break;
384        case I2C_SMBUS_BYTE:
385                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
386                       SMBHSTADD);
387                if (read_write == I2C_SMBUS_WRITE)
388                        outb_p(command, SMBHSTCMD);
389                size = PIIX4_BYTE;
390                break;
391        case I2C_SMBUS_BYTE_DATA:
392                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
393                       SMBHSTADD);
394                outb_p(command, SMBHSTCMD);
395                if (read_write == I2C_SMBUS_WRITE)
396                        outb_p(data->byte, SMBHSTDAT0);
397                size = PIIX4_BYTE_DATA;
398                break;
399        case I2C_SMBUS_WORD_DATA:
400                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
401                       SMBHSTADD);
402                outb_p(command, SMBHSTCMD);
403                if (read_write == I2C_SMBUS_WRITE) {
404                        outb_p(data->word & 0xff, SMBHSTDAT0);
405                        outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
406                }
407                size = PIIX4_WORD_DATA;
408                break;
409        case I2C_SMBUS_BLOCK_DATA:
410                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
411                       SMBHSTADD);
412                outb_p(command, SMBHSTCMD);
413                if (read_write == I2C_SMBUS_WRITE) {
414                        len = data->block[0];
415                        if (len < 0)
416                                len = 0;
417                        if (len > 32)
418                                len = 32;
419                        outb_p(len, SMBHSTDAT0);
420                        i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
421                        for (i = 1; i <= len; i++)
422                                outb_p(data->block[i], SMBBLKDAT);
423                }
424                size = PIIX4_BLOCK_DATA;
425                break;
426        }
427
428        outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
429
430        if (piix4_transaction())        /* Error in transaction */
431                return -1;
432
433        if ((read_write == I2C_SMBUS_WRITE) || (size == PIIX4_QUICK))
434                return 0;
435
436
437        switch (size) {
438        case PIIX4_BYTE:        /* Where is the result put? I assume here it is in
439                                   SMBHSTDAT0 but it might just as well be in the
440                                   SMBHSTCMD. No clue in the docs */
441
442                data->byte = inb_p(SMBHSTDAT0);
443                break;
444        case PIIX4_BYTE_DATA:
445                data->byte = inb_p(SMBHSTDAT0);
446                break;
447        case PIIX4_WORD_DATA:
448                data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
449                break;
450        case PIIX4_BLOCK_DATA:
451                data->block[0] = inb_p(SMBHSTDAT0);
452                i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
453                for (i = 1; i <= data->block[0]; i++)
454                        data->block[i] = inb_p(SMBBLKDAT);
455                break;
456        }
457        return 0;
458}
459
460
461u32 piix4_func(struct i2c_adapter *adapter)
462{
463        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
464            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
465            I2C_FUNC_SMBUS_BLOCK_DATA;
466}
467
468static struct i2c_algorithm smbus_algorithm = {
469        .name           = "Non-I2C SMBus adapter",
470        .id             = I2C_ALGO_SMBUS,
471        .smbus_xfer     = piix4_access,
472        .functionality  = piix4_func,
473};
474
475static struct i2c_adapter piix4_adapter = {
476        .owner          = THIS_MODULE,
477        .name           = "unset",
478        .id             = I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4,
479        .algo           = &smbus_algorithm,
480};
481
482
483
484static struct pci_device_id piix4_ids[] __devinitdata = {
485        { 0, }
486};
487
488static int __devinit piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
489{
490
491        sprintf(piix4_adapter.name, "SMBus PIIX4 adapter at %04x",
492                piix4_smba);
493
494        i2c_add_adapter(&piix4_adapter);
495}
496
497static void __devexit piix4_remove(struct pci_dev *dev)
498{
499        i2c_del_adapter(&piix4_adapter);
500}
501
502
503static struct pci_driver piix4_driver = {
504        .name           = "piix4 smbus",
505        .id_table       = piix4_ids,
506        .probe          = piix4_probe,
507        .remove         = __devexit_p(piix4_remove),
508};
509
510static int __init i2c_piix4_init(void)
511{
512        printk("i2c-piix4.o version %s (%s)\n", LM_VERSION, LM_DATE);
513        return pci_module_init(&piix4_driver);
514}
515
516
517static void __exit i2c_piix4_exit(void)
518{
519        pci_unregister_driver(&piix4_driver);
520        release_region(piix4_smba, 8);
521}
522
523
524
525MODULE_AUTHOR
526    ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
527MODULE_DESCRIPTION("PIIX4 SMBus driver");
528MODULE_LICENSE("GPL");
529
530module_init(i2c_piix4_init);
531module_exit(i2c_piix4_exit);
Note: See TracBrowser for help on using the browser.