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

Revision 1595, 14.6 KB (checked in by mds, 11 years ago)

8235 take 2

  • 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/version.h>
36#include <linux/module.h>
37#include <linux/pci.h>
38#include <asm/io.h>
39#include <linux/kernel.h>
40#include <linux/stddef.h>
41#include <linux/sched.h>
42#include <linux/ioport.h>
43#include <linux/i2c.h>
44#include "version.h"
45#include <linux/init.h>
46
47#ifndef PCI_DEVICE_ID_VIA_82C596_3
48#define PCI_DEVICE_ID_VIA_82C596_3      0x3050
49#endif
50#ifndef PCI_DEVICE_ID_VIA_82C596B_3
51#define PCI_DEVICE_ID_VIA_82C596B_3     0x3051
52#endif
53#ifndef PCI_DEVICE_ID_VIA_82C686_4
54#define PCI_DEVICE_ID_VIA_82C686_4      0x3057
55#endif
56#ifndef PCI_DEVICE_ID_VIA_8233_0
57#define PCI_DEVICE_ID_VIA_8233_0        0x3074
58#endif
59
60#define SMBBA1      0x90
61#define SMBBA2      0x80
62#define SMBBA3      0xD0
63
64struct sd {
65        const unsigned short dev;
66        const unsigned char base;
67        const unsigned char hstcfg;
68        const char *name;
69};
70
71static struct sd supported[] = {
72        {PCI_DEVICE_ID_VIA_82C596_3, SMBBA1, 0xD2, "VT82C596A/B"},
73        {PCI_DEVICE_ID_VIA_82C596B_3, SMBBA1, 0xD2, "VT82C596B"},
74        {PCI_DEVICE_ID_VIA_82C686_4, SMBBA1, 0xD2, "VT82C686A/B"},
75        {PCI_DEVICE_ID_VIA_8233_0, SMBBA3, 0xD2, "VT8233"},
76        {0x3147, SMBBA3, 0xD2, "VT8233A"},
77        {0x3177, SMBBA3, 0xD2, "VT8233A/8235"},
78        {0x8235, SMBBA1, 0xD2, "VT8231"},
79        {0, 0, 0, NULL}
80};
81
82static struct sd *num = supported;
83
84/* SMBus address offsets */
85#define SMBHSTSTS (0 + vt596_smba)
86#define SMBHSLVSTS (1 + vt596_smba)
87#define SMBHSTCNT (2 + vt596_smba)
88#define SMBHSTCMD (3 + vt596_smba)
89#define SMBHSTADD (4 + vt596_smba)
90#define SMBHSTDAT0 (5 + vt596_smba)
91#define SMBHSTDAT1 (6 + vt596_smba)
92#define SMBBLKDAT (7 + vt596_smba)
93#define SMBSLVCNT (8 + vt596_smba)
94#define SMBSHDWCMD (9 + vt596_smba)
95#define SMBSLVEVT (0xA + vt596_smba)
96#define SMBSLVDAT (0xC + vt596_smba)
97
98/* PCI Address Constants */
99
100/* SMBus data in configuration space can be found in two places,
101   We try to select the better one*/
102
103static unsigned short smb_cf_hstcfg;
104
105#define SMBHSTCFG   (smb_cf_hstcfg)
106#define SMBSLVC     (SMBHSTCFG+1)
107#define SMBSHDW1    (SMBHSTCFG+2)
108#define SMBSHDW2    (SMBHSTCFG+3)
109#define SMBREV      (SMBHSTCFG+4)
110
111/* Other settings */
112#define MAX_TIMEOUT 500
113#define  ENABLE_INT9 0
114
115/* VT82C596 constants */
116#define VT596_QUICK      0x00
117#define VT596_BYTE       0x04
118#define VT596_BYTE_DATA  0x08
119#define VT596_WORD_DATA  0x0C
120#define VT596_BLOCK_DATA 0x14
121
122/* insmod parameters */
123
124/* If force is set to anything different from 0, we forcibly enable the
125   VT596. DANGEROUS! */
126static int force = 0;
127MODULE_PARM(force, "i");
128MODULE_PARM_DESC(force, "Forcibly enable the SMBus. DANGEROUS!");
129
130/* If force_addr is set to anything different from 0, we forcibly enable
131   the VT596 at the given address. VERY DANGEROUS! */
132static int force_addr = 0;
133MODULE_PARM(force_addr, "i");
134MODULE_PARM_DESC(force_addr,
135                 "Forcibly enable the SMBus at the given address. "
136                 "EXTREMELY DANGEROUS!");
137
138#ifdef MODULE
139static
140#else
141extern
142#endif
143int __init i2c_vt596_init(void);
144static int __init vt596_cleanup(void);
145static int vt596_setup(void);
146static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
147                        unsigned short flags, char read_write,
148                        u8 command, int size, union i2c_smbus_data *data);
149static void vt596_do_pause(unsigned int amount);
150static int vt596_transaction(void);
151static void vt596_inc(struct i2c_adapter *adapter);
152static void vt596_dec(struct i2c_adapter *adapter);
153static u32 vt596_func(struct i2c_adapter *adapter);
154
155#ifdef MODULE
156extern int init_module(void);
157extern int cleanup_module(void);
158#endif                          /* MODULE */
159
160static struct i2c_algorithm smbus_algorithm = {
161        /* name */ "Non-I2C SMBus adapter",
162        /* id */ I2C_ALGO_SMBUS,
163        /* master_xfer */ NULL,
164        /* smbus_access */ vt596_access,
165        /* slave_send */ NULL,
166        /* slave_rcv */ NULL,
167        /* algo_control */ NULL,
168        /* functionality */ vt596_func,
169};
170
171static struct i2c_adapter vt596_adapter = {
172        "unset",
173        I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2,
174        &smbus_algorithm,
175        NULL,
176        vt596_inc,
177        vt596_dec,
178        NULL,
179        NULL,
180};
181
182static int __initdata vt596_initialized;
183static unsigned short vt596_smba = 0;
184
185
186/* Detect whether a compatible device can be found, and initialize it. */
187int vt596_setup(void)
188{
189        unsigned char temp;
190
191        struct pci_dev *VT596_dev = NULL;
192
193        /* First check whether we can access PCI at all */
194        if (pci_present() == 0)
195                return(-ENODEV);
196
197        /* Look for a supported device/function */
198        do {
199                if((VT596_dev = pci_find_device(PCI_VENDOR_ID_VIA, num->dev,
200                                                VT596_dev)))
201                        break;
202        } while ((++num)->dev);
203
204        if (VT596_dev == NULL)
205                return(-ENODEV);
206        printk("i2c-viapro.o: Found Via %s device\n", num->name);
207
208/* Determine the address of the SMBus areas */
209        smb_cf_hstcfg = num->hstcfg;
210        if (force_addr) {
211                vt596_smba = force_addr & 0xfff0;
212                force = 0;
213        } else {
214                if ((pci_read_config_word(VT596_dev, num->base, &vt596_smba))
215                    || !(vt596_smba & 0x1)) {
216                        /* try 2nd address and config reg. for 596 */
217                        if((num->dev == PCI_DEVICE_ID_VIA_82C596_3) &&
218                           (!pci_read_config_word(VT596_dev, SMBBA2, &vt596_smba)) &&
219                           (vt596_smba & 0x1)) {
220                                smb_cf_hstcfg = 0x84;
221                        } else {
222                                /* no matches at all */
223                                printk("i2c-viapro.o: Cannot configure SMBus "
224                                       "I/O Base address\n");
225                                return(-ENODEV);
226                        }
227                }
228                vt596_smba &= 0xfff0;
229                if(vt596_smba == 0) {
230                        printk(KERN_ERR "i2c-viapro.o: SMBus base address"
231                           "uninitialized - upgrade BIOS or use force_addr=0xaddr\n");
232                        return -ENODEV;
233                }
234        }
235
236        if (check_region(vt596_smba, 8)) {
237                printk("i2c-viapro.o: SMBus region 0x%x already in use!\n",
238                        vt596_smba);
239                return(-ENODEV);
240        }
241
242        pci_read_config_byte(VT596_dev, SMBHSTCFG, &temp);
243/* If force_addr is set, we program the new address here. Just to make
244   sure, we disable the VT596 first. */
245        if (force_addr) {
246                pci_write_config_byte(VT596_dev, SMBHSTCFG, temp & 0xfe);
247                pci_write_config_word(VT596_dev, num->base, vt596_smba);
248                pci_write_config_byte(VT596_dev, SMBHSTCFG, temp | 0x01);
249                printk
250                    ("i2c-viapro.o: WARNING: SMBus interface set to new "
251                     "address 0x%04x!\n", vt596_smba);
252        } else if ((temp & 1) == 0) {
253                if (force) {
254/* NOTE: This assumes I/O space and other allocations WERE
255   done by the Bios!  Don't complain if your hardware does weird
256   things after enabling this. :') Check for Bios updates before
257   resorting to this.  */
258                        pci_write_config_byte(VT596_dev, SMBHSTCFG,
259                                              temp | 1);
260                        printk
261                            ("i2c-viapro.o: enabling SMBus device\n");
262                } else {
263                        printk
264                            ("SMBUS: Error: Host SMBus controller not enabled! - "
265                             "upgrade BIOS or use force=1\n");
266                        return(-ENODEV);
267                }
268        }
269
270        /* Everything is happy, let's grab the memory and set things up. */
271        request_region(vt596_smba, 8, "viapro-smbus");
272
273#ifdef DEBUG
274        if ((temp & 0x0E) == 8)
275                printk("i2c-viapro.o: using Interrupt 9 for SMBus.\n");
276        else if ((temp & 0x0E) == 0)
277                printk("i2c-viapro.o: using Interrupt SMI# for SMBus.\n");
278        else
279                printk
280                    ("i2c-viapro.o: Illegal Interrupt configuration (or code out "
281                     "of date)!\n");
282
283        pci_read_config_byte(VT596_dev, SMBREV, &temp);
284        printk("i2c-viapro.o: SMBREV = 0x%X\n", temp);
285        printk("i2c-viapro.o: VT596_smba = 0x%X\n", vt596_smba);
286#endif                          /* DEBUG */
287
288        return(0);
289}
290
291
292/* Internally used pause function */
293void vt596_do_pause(unsigned int amount)
294{
295        current->state = TASK_INTERRUPTIBLE;
296        schedule_timeout(amount);
297}
298
299/* Another internally used function */
300int vt596_transaction(void)
301{
302        int temp;
303        int result = 0;
304        int timeout = 0;
305
306#ifdef DEBUG
307        printk
308            ("i2c-viapro.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
309             "DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
310             inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
311#endif
312
313        /* Make sure the SMBus host is ready to start transmitting */
314        if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
315#ifdef DEBUG
316                printk("i2c-viapro.o: SMBus busy (0x%02x). Resetting... \n",
317                       temp);
318#endif
319                outb_p(temp, SMBHSTSTS);
320                if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
321#ifdef DEBUG
322                        printk("i2c-viapro.o: Failed! (0x%02x)\n", temp);
323#endif
324                        return -1;
325                } else {
326#ifdef DEBUG
327                        printk("i2c-viapro.o: Successfull!\n");
328#endif
329                }
330        }
331
332        /* start the transaction by setting bit 6 */
333        outb_p(inb(SMBHSTCNT) | 0x040, SMBHSTCNT);
334
335        /* We will always wait for a fraction of a second!
336           I don't know if VIA needs this, Intel did  */
337        do {
338                vt596_do_pause(1);
339                temp = inb_p(SMBHSTSTS);
340        } while ((temp & 0x01) && (timeout++ < MAX_TIMEOUT));
341
342        /* If the SMBus is still busy, we give up */
343        if (timeout >= MAX_TIMEOUT) {
344#ifdef DEBUG
345                printk("i2c-viapro.o: SMBus Timeout!\n");
346                result = -1;
347#endif
348        }
349
350        if (temp & 0x10) {
351                result = -1;
352#ifdef DEBUG
353                printk("i2c-viapro.o: Error: Failed bus transaction\n");
354#endif
355        }
356
357        if (temp & 0x08) {
358                result = -1;
359                printk
360                    ("i2c-viapro.o: Bus collision! SMBus may be locked until next hard\n"
361                     "reset. (sorry!)\n");
362                /* Clock stops and slave is stuck in mid-transmission */
363        }
364
365        if (temp & 0x04) {
366                result = -1;
367#ifdef DEBUG
368                printk("i2c-viapro.o: Error: no response!\n");
369#endif
370        }
371
372        if (inb_p(SMBHSTSTS) != 0x00)
373                outb_p(inb(SMBHSTSTS), SMBHSTSTS);
374
375        if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
376#ifdef DEBUG
377                printk
378                    ("i2c-viapro.o: Failed reset at end of transaction (%02x)\n",
379                     temp);
380#endif
381        }
382#ifdef DEBUG
383        printk
384            ("i2c-viapro.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
385             "DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTCNT), inb_p(SMBHSTCMD),
386             inb_p(SMBHSTADD), inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
387#endif
388        return result;
389}
390
391/* Return -1 on error. */
392s32 vt596_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
393                 char read_write,
394                 u8 command, int size, union i2c_smbus_data * data)
395{
396        int i, len;
397
398        switch (size) {
399        case I2C_SMBUS_PROC_CALL:
400                printk
401                    ("i2c-viapro.o: I2C_SMBUS_PROC_CALL not supported!\n");
402                return -1;
403        case I2C_SMBUS_QUICK:
404                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
405                       SMBHSTADD);
406                size = VT596_QUICK;
407                break;
408        case I2C_SMBUS_BYTE:
409                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
410                       SMBHSTADD);
411                if (read_write == I2C_SMBUS_WRITE)
412                        outb_p(command, SMBHSTCMD);
413                size = VT596_BYTE;
414                break;
415        case I2C_SMBUS_BYTE_DATA:
416                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
417                       SMBHSTADD);
418                outb_p(command, SMBHSTCMD);
419                if (read_write == I2C_SMBUS_WRITE)
420                        outb_p(data->byte, SMBHSTDAT0);
421                size = VT596_BYTE_DATA;
422                break;
423        case I2C_SMBUS_WORD_DATA:
424                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
425                       SMBHSTADD);
426                outb_p(command, SMBHSTCMD);
427                if (read_write == I2C_SMBUS_WRITE) {
428                        outb_p(data->word & 0xff, SMBHSTDAT0);
429                        outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
430                }
431                size = VT596_WORD_DATA;
432                break;
433        case I2C_SMBUS_BLOCK_DATA:
434                outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
435                       SMBHSTADD);
436                outb_p(command, SMBHSTCMD);
437                if (read_write == I2C_SMBUS_WRITE) {
438                        len = data->block[0];
439                        if (len < 0)
440                                len = 0;
441                        if (len > 32)
442                                len = 32;
443                        outb_p(len, SMBHSTDAT0);
444                        i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
445                        for (i = 1; i <= len; i++)
446                                outb_p(data->block[i], SMBBLKDAT);
447                }
448                size = VT596_BLOCK_DATA;
449                break;
450        }
451
452        outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT);
453
454        if (vt596_transaction())        /* Error in transaction */
455                return -1;
456
457        if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
458                return 0;
459
460
461        switch (size) {
462        case VT596_BYTE:        /* Where is the result put? I assume here it is in
463                                   SMBHSTDAT0 but it might just as well be in the
464                                   SMBHSTCMD. No clue in the docs */
465
466                data->byte = inb_p(SMBHSTDAT0);
467                break;
468        case VT596_BYTE_DATA:
469                data->byte = inb_p(SMBHSTDAT0);
470                break;
471        case VT596_WORD_DATA:
472                data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
473                break;
474        case VT596_BLOCK_DATA:
475                data->block[0] = inb_p(SMBHSTDAT0);
476                i = inb_p(SMBHSTCNT);   /* Reset SMBBLKDAT */
477                for (i = 1; i <= data->block[0]; i++)
478                        data->block[i] = inb_p(SMBBLKDAT);
479                break;
480        }
481        return 0;
482}
483
484void vt596_inc(struct i2c_adapter *adapter)
485{
486        MOD_INC_USE_COUNT;
487}
488
489void vt596_dec(struct i2c_adapter *adapter)
490{
491
492        MOD_DEC_USE_COUNT;
493}
494
495u32 vt596_func(struct i2c_adapter *adapter)
496{
497        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
498            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
499            I2C_FUNC_SMBUS_BLOCK_DATA;
500}
501
502int __init i2c_vt596_init(void)
503{
504        int res;
505        printk("i2c-viapro.o version %s (%s)\n", LM_VERSION, LM_DATE);
506#ifdef DEBUG
507/* PE- It might be good to make this a permanent part of the code! */
508        if (vt596_initialized) {
509                printk
510                    ("i2c-viapro.o: Oops, vt596_init called a second time!\n");
511                return -EBUSY;
512        }
513#endif
514        vt596_initialized = 0;
515        if ((res = vt596_setup())) {
516                printk
517                    ("i2c-viapro.o: Can't detect vt82c596 or compatible device, module not inserted.\n");
518                vt596_cleanup();
519                return res;
520        }
521        vt596_initialized++;
522        sprintf(vt596_adapter.name, "SMBus Via Pro adapter at %04x",
523                vt596_smba);
524        if ((res = i2c_add_adapter(&vt596_adapter))) {
525                printk
526                    ("i2c-viapro.o: Adapter registration failed, module not inserted.\n");
527                vt596_cleanup();
528                return res;
529        }
530        vt596_initialized++;
531        printk("i2c-viapro.o: Via Pro SMBus detected and initialized\n");
532        return 0;
533}
534
535int __init vt596_cleanup(void)
536{
537        int res;
538        if (vt596_initialized >= 2) {
539                if ((res = i2c_del_adapter(&vt596_adapter))) {
540                        printk
541                            ("i2c-viapro.o: i2c_del_adapter failed, module not removed\n");
542                        return res;
543                } else
544                        vt596_initialized--;
545        }
546        if (vt596_initialized >= 1) {
547                release_region(vt596_smba, 8);
548                vt596_initialized--;
549        }
550        return 0;
551}
552
553EXPORT_NO_SYMBOLS;
554
555#ifdef MODULE
556
557MODULE_AUTHOR
558    ("Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>");
559MODULE_DESCRIPTION("vt82c596 SMBus driver");
560
561#ifdef MODULE_LICENSE
562MODULE_LICENSE("GPL");
563#endif
564
565int init_module(void)
566{
567        return i2c_vt596_init();
568}
569
570int cleanup_module(void)
571{
572        return vt596_cleanup();
573}
574
575#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.