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

Revision 1152, 14.2 KB (checked in by phil, 12 years ago)

(Phil) Patches from Mark Rusk to support Serverworks CSB5.

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