root/lm-sensors/trunk/kernel/busses/i2c-amd756.c @ 707

Revision 707, 12.9 KB (checked in by frodo, 15 years ago)

`indent -kr -i8' on all kernel sources

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2    amd756.c - Part of lm_sensors, Linux kernel modules for hardware
3              monitoring
4
5    Copyright (c) 1999 Merlin Hughes <merlin@merlin.org>
6
7    Shamelessly ripped from i2c-piix4.c:
8
9    Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
10    Philip Edelbrock <phil@netroedge.com>
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*/
26
27/* Note: we assume there can only be one AMD756, with one SMBus interface */
28
29#include <linux/version.h>
30#include <linux/module.h>
31#include <linux/pci.h>
32#include <asm/io.h>
33#include <linux/kernel.h>
34#include <linux/stddef.h>
35#include <linux/sched.h>
36#include <linux/ioport.h>
37#include <linux/i2c.h>
38#include "version.h"
39
40#include <linux/init.h>
41
42/* AMD756 SMBus address offsets */
43#define SMB_GLOBAL_STATUS      (0xE0 + amd756_smba)
44#define SMB_GLOBAL_ENABLE      (0xE2 + amd756_smba)
45#define SMB_HOST_ADDRESS       (0xE4 + amd756_smba)
46#define SMB_HOST_DATA          (0xE6 + amd756_smba)
47#define SMB_HOST_COMMAND       (0xE8 + amd756_smba)
48#define SMB_HOST_BLOCK_DATA    (0xE9 + amd756_smba)
49#define SMB_HAS_DATA           (0xEA + amd756_smba)
50#define SMB_HAS_DEVICE_ADDRESS (0xEC + amd756_smba)
51#define SMB_HAS_HOST_ADDRESS   (0xEE + amd756_smba)
52#define SMB_SNOOP_ADDRESS      (0xEF + amd756_smba)
53
54/* PCI Address Constants */
55
56/* address of I/O space */
57#define SMBBA     0x058         /* mh */
58
59/* general configuration */
60#define SMBGCFG   0x041         /* mh */
61
62/* silicon revision code */
63#define SMBREV    0x008
64
65/* Other settings */
66#define MAX_TIMEOUT 500
67
68/* AMD756 constants */
69#define AMD756_QUICK        0x00
70#define AMD756_BYTE         0x01
71#define AMD756_BYTE_DATA    0x02
72#define AMD756_WORD_DATA    0x03
73#define AMD756_PROCESS_CALL 0x04
74#define AMD756_BLOCK_DATA   0x05
75
76/* insmod parameters */
77
78#ifdef MODULE
79static
80#else
81extern
82#endif
83int __init i2c_amd756_init(void);
84static int __init amd756_cleanup(void);
85static int amd756_setup(void);
86static s32 amd756_access(struct i2c_adapter *adap, u16 addr,
87                         unsigned short flags, char read_write,
88                         u8 command, int size, union i2c_smbus_data *data);
89static void amd756_do_pause(unsigned int amount);
90static int amd756_transaction(void);
91static void amd756_inc(struct i2c_adapter *adapter);
92static void amd756_dec(struct i2c_adapter *adapter);
93static u32 amd756_func(struct i2c_adapter *adapter);
94
95#ifdef MODULE
96extern int init_module(void);
97extern int cleanup_module(void);
98#endif                          /* MODULE */
99
100static struct i2c_algorithm smbus_algorithm = {
101        /* name */ "Non-I2C SMBus adapter",
102        /* id */ I2C_ALGO_SMBUS,
103        /* master_xfer */ NULL,
104        /* smbus_access */ amd756_access,
105        /* slave_send */ NULL,
106        /* slave_rcv */ NULL,
107        /* algo_control */ NULL,
108        /* functionality */ amd756_func,
109};
110
111static struct i2c_adapter amd756_adapter = {
112        "unset",
113        I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756,
114        &smbus_algorithm,
115        NULL,
116        amd756_inc,
117        amd756_dec,
118        NULL,
119        NULL,
120};
121
122static int __initdata amd756_initialized;
123static unsigned short amd756_smba = 0;
124
125/* externalize it */
126#define PCI_DEVICE_ID_AMD_756 0x740B
127
128/* Detect whether a AMD756 can be found, and initialize it, where necessary.
129   Note the differences between kernels with the old PCI BIOS interface and
130   newer kernels with the real PCI interface. In compat.h some things are
131   defined to make the transition easier. */
132int amd756_setup(void)
133{
134        int error_return = 0;
135        unsigned char temp;
136
137        struct pci_dev *AMD756_dev;
138
139        /* First check whether we can access PCI at all */
140        if (pci_present() == 0) {
141                printk("i2c-amd756.o: Error: No PCI-bus found!\n");
142                error_return = -ENODEV;
143                goto END;
144        }
145
146        /* Look for the AMD756, function 3 */
147        /* Note: we keep on searching until we have found 'function 3' */
148        AMD756_dev = NULL;
149        do
150                AMD756_dev = pci_find_device(PCI_VENDOR_ID_AMD,
151                                             PCI_DEVICE_ID_AMD_756,
152                                             AMD756_dev);
153        while (AMD756_dev && (PCI_FUNC(AMD756_dev->devfn) != 3));
154        if (AMD756_dev == NULL) {
155                printk
156                    ("i2c-amd756.o: Error: Can't detect AMD756, function 3!\n");
157                error_return = -ENODEV;
158                goto END;
159        }
160
161/* Determine the address of the SMBus areas */
162
163        /* Technically it is a dword but... */
164        pci_read_config_word(AMD756_dev, SMBBA, &amd756_smba);
165        amd756_smba &= 0xfff0;
166
167        if (check_region(amd756_smba, 8)) {
168                printk
169                    ("i2c-amd756.o: AMD756_smb region 0x%x already in use!\n",
170                     amd756_smba);
171                error_return = -ENODEV;
172                goto END;
173        }
174
175        pci_read_config_byte(AMD756_dev, SMBGCFG, &temp);
176
177        if ((temp & 128) == 0) {
178                printk
179                    ("SMBUS: Error: Host SMBus controller I/O not enabled!\n");
180                error_return = -ENODEV;
181                goto END;
182        }
183
184        /* Everything is happy, let's grab the memory and set things up. */
185        request_region(amd756_smba, 8, "amd756-smbus");
186
187#ifdef DEBUG
188        /*
189           if ((temp & 0x0E) == 8)
190           printk("i2c-amd756.o: AMD756 using Interrupt 9 for SMBus.\n");
191           else if ((temp & 0x0E) == 0)
192           printk("i2c-amd756.o: AMD756 using Interrupt SMI# for SMBus.\n");
193           else
194           printk("i2c-amd756.o: AMD756: Illegal Interrupt configuration (or code out "
195           "of date)!\n");
196         */
197
198        pci_read_config_byte(AMD756_dev, SMBREV, &temp);
199        printk("i2c-amd756.o: SMBREV = 0x%X\n", temp);
200        printk("i2c-amd756.o: AMD756_smba = 0x%X\n", amd756_smba);
201#endif                          /* DEBUG */
202
203      END:
204        return error_return;
205}
206
207/*
208  SMBUS event = I/O 28-29 bit 11
209     see E0 for the status bits and enabled in E2
210     
211*/
212
213/* Internally used pause function */
214void amd756_do_pause(unsigned int amount)
215{
216        current->state = TASK_INTERRUPTIBLE;
217        schedule_timeout(amount);
218}
219
220#define GS_ABRT_STS (1 << 0)
221#define GS_COL_STS (1 << 1)
222#define GS_PRERR_STS (1 << 2)
223#define GS_HST_STS (1 << 3)
224#define GS_HCYC_STS (1 << 4)
225#define GS_TO_STS (1 << 5)
226
227#define GS_CLEAR_STS (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
228  GS_HCYC_STS | GS_TO_STS )
229
230#define GE_CYC_TYPE_MASK (7)
231#define GE_HOST_STC (1 << 3)
232
233/* Another internally used function */
234int amd756_transaction(void)
235{
236        int temp;
237        int result = 0;
238        int timeout = 0;
239
240#ifdef DEBUG
241        printk
242            ("i2c-amd756.o: Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
243             inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
244             inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
245#endif
246
247        /* Make sure the SMBus host is ready to start transmitting */
248        /* TODO: What about SM_BSY? */
249        if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_HST_STS) != 0x00) {
250#ifdef DEBUG
251                printk
252                    ("i2c-amd756.o: SMBus busy (%04x). Resetting (NOT)... \n",
253                     temp);
254#endif
255                /* TODO: How to reset the AMD?
256                   outb_p(temp, SMBHSTSTS);
257                 */
258                if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_HST_STS) !=
259                    0x00) {
260#ifdef DEBUG
261                        printk("i2c-amd756.o: Failed! (%04x)\n", temp);
262#endif
263                        return -1;
264                } else {
265#ifdef DEBUG
266                        printk("i2c-amd756.o: Successfull!\n");
267#endif
268                }
269        }
270
271        /* start the transaction by setting bit 6 */
272        outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
273
274        /* We will always wait for a fraction of a second! */
275        do {
276                amd756_do_pause(1);
277                temp = inw_p(SMB_GLOBAL_STATUS);
278        } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
279
280        /* If the SMBus is still busy, we give up */
281        if (timeout >= MAX_TIMEOUT) {
282#ifdef DEBUG
283                printk("i2c-amd756.o: SMBus explicit timeout!\n");
284                result = -1;
285#endif
286        }
287
288        if (temp & GS_PRERR_STS) {
289                result = -1;
290#ifdef DEBUG
291                printk("i2c-amd756.o: SMBus Protocol error!\n");
292#endif
293        }
294
295        if (temp & GS_COL_STS) {
296                result = -1;
297                printk("i2c-amd756.o: SMBus collision!\n");
298                /* TODO: Clear Collision Status with a 1 */
299        }
300
301        if (temp & GS_TO_STS) {
302                result = -1;
303#ifdef DEBUG
304                printk("i2c-amd756.o: SMBus protocol timeout!\n");
305#endif
306        }
307#ifdef DEBUG
308        if (temp & GS_HCYC_STS) {
309                printk("i2c-amd756.o: SMBus protocol success!\n");
310        }
311#endif
312
313        outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
314
315        if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
316#ifdef DEBUG
317                printk
318                    ("i2c-amd756.o: Failed reset at end of transaction (%04x)\n",
319                     temp);
320#endif
321        }
322#ifdef DEBUG
323        printk
324            ("i2c-amd756.o: Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
325             inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
326             inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
327#endif
328
329        return result;
330}
331
332/* Return -1 on error. See smbus.h for more information */
333s32 amd756_access(struct i2c_adapter * adap, u16 addr,
334                  unsigned short flags, char read_write,
335                  u8 command, int size, union i2c_smbus_data * data)
336{
337        int i, len;
338
339  /** TODO: Should I supporte the 10-bit transfers? */
340        switch (size) {
341        case I2C_SMBUS_PROC_CALL:
342                printk
343                    ("i2c-amd756.o: I2C_SMBUS_PROC_CALL not supported!\n");
344                /* TODO: Well... It is supported, I'm just not sure what to do here... */
345                return -1;
346        case I2C_SMBUS_QUICK:
347                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
348                       SMB_HOST_ADDRESS);
349                size = AMD756_QUICK;
350                break;
351        case I2C_SMBUS_BYTE:
352                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
353                       SMB_HOST_ADDRESS);
354                /* TODO: Why only during write? */
355                if (read_write == I2C_SMBUS_WRITE)
356                        outb_p(command, SMB_HOST_COMMAND);
357                size = AMD756_BYTE;
358                break;
359        case I2C_SMBUS_BYTE_DATA:
360                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
361                       SMB_HOST_ADDRESS);
362                outb_p(command, SMB_HOST_COMMAND);
363                if (read_write == I2C_SMBUS_WRITE)
364                        outw_p(data->byte, SMB_HOST_DATA);
365                size = AMD756_BYTE_DATA;
366                break;
367        case I2C_SMBUS_WORD_DATA:
368                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
369                       SMB_HOST_ADDRESS);
370                outb_p(command, SMB_HOST_COMMAND);
371                if (read_write == I2C_SMBUS_WRITE)
372                        outw_p(data->word, SMB_HOST_DATA);      /* TODO: endian???? */
373                size = AMD756_WORD_DATA;
374                break;
375        case I2C_SMBUS_BLOCK_DATA:
376                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
377                       SMB_HOST_ADDRESS);
378                outb_p(command, SMB_HOST_COMMAND);
379                if (read_write == I2C_SMBUS_WRITE) {
380                        len = data->block[0];
381                        if (len < 0)
382                                len = 0;
383                        if (len > 32)
384                                len = 32;
385                        outw_p(len, SMB_HOST_DATA);
386                        /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
387                        for (i = 1; i <= len; i++)
388                                outb_p(data->block[i],
389                                       SMB_HOST_BLOCK_DATA);
390                }
391                size = AMD756_BLOCK_DATA;
392                break;
393        }
394
395        /* How about enabling interrupts... */
396        outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
397
398        if (amd756_transaction())       /* Error in transaction */
399                return -1;
400
401        if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
402                return 0;
403
404
405        switch (size) {
406        case AMD756_BYTE:
407                data->byte = inw_p(SMB_HOST_DATA);
408                break;
409        case AMD756_BYTE_DATA:
410                data->byte = inw_p(SMB_HOST_DATA);
411                break;
412        case AMD756_WORD_DATA:
413                data->word = inw_p(SMB_HOST_DATA);      /* TODO: endian???? */
414                break;
415        case AMD756_BLOCK_DATA:
416                data->block[0] = inw_p(SMB_HOST_DATA & 63);
417                /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
418                for (i = 1; i <= data->block[0]; i++)
419                        data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
420                break;
421        }
422
423        return 0;
424}
425
426void amd756_inc(struct i2c_adapter *adapter)
427{
428        MOD_INC_USE_COUNT;
429}
430
431void amd756_dec(struct i2c_adapter *adapter)
432{
433
434        MOD_DEC_USE_COUNT;
435}
436
437u32 amd756_func(struct i2c_adapter *adapter)
438{
439        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
440            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
441            I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
442}
443
444int __init i2c_amd756_init(void)
445{
446        int res;
447        printk("amd756.o version %s (%s)\n", LM_VERSION, LM_DATE);
448#ifdef DEBUG
449/* PE- It might be good to make this a permanent part of the code! */
450        if (amd756_initialized) {
451                printk
452                    ("i2c-amd756.o: Oops, amd756_init called a second time!\n");
453                return -EBUSY;
454        }
455#endif
456        amd756_initialized = 0;
457        if ((res = amd756_setup())) {
458                printk
459                    ("i2c-amd756.o: AMD756 not detected, module not inserted.\n");
460                amd756_cleanup();
461                return res;
462        }
463        amd756_initialized++;
464        sprintf(amd756_adapter.name, "SMBus AMD756 adapter at %04x",
465                amd756_smba);
466        if ((res = i2c_add_adapter(&amd756_adapter))) {
467                printk
468                    ("i2c-amd756.o: Adapter registration failed, module not inserted.\n");
469                amd756_cleanup();
470                return res;
471        }
472        amd756_initialized++;
473        printk("i2c-amd756.o: AMD756 bus detected and initialized\n");
474        return 0;
475}
476
477int __init amd756_cleanup(void)
478{
479        int res;
480        if (amd756_initialized >= 2) {
481                if ((res = i2c_del_adapter(&amd756_adapter))) {
482                        printk
483                            ("i2c-amd756.o: i2c_del_adapter failed, module not removed\n");
484                        return res;
485                } else
486                        amd756_initialized--;
487        }
488        if (amd756_initialized >= 1) {
489                release_region(amd756_smba, 8);
490                amd756_initialized--;
491        }
492        return 0;
493}
494
495EXPORT_NO_SYMBOLS;
496
497#ifdef MODULE
498
499MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
500MODULE_DESCRIPTION("AMD756 SMBus driver");
501
502int init_module(void)
503{
504        return i2c_amd756_init();
505}
506
507int cleanup_module(void)
508{
509        return amd756_cleanup();
510}
511
512#endif                          /* MODULE */
Note: See TracBrowser for help on using the browser.