Subversion Repositories shark

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
420 giacomo 1
/*
2
    amd756.c - Part of lm_sensors, Linux kernel modules for hardware
3
              monitoring
4
 
5
    Copyright (c) 1999-2002 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
/*
28
    2002-04-08: Added nForce support. (Csaba Halasz)
29
    2002-10-03: Fixed nForce PnP I/O port. (Michael Steil)
30
    2002-12-28: Rewritten into something that resembles a Linux driver (hch)
31
*/
32
 
33
/*
34
   Supports AMD756, AMD766, AMD768 and nVidia nForce
35
   Note: we assume there can only be one device, with one SMBus interface.
36
*/
37
 
38
/* #define DEBUG 1 */
39
 
40
#include <linux/module.h>
41
#include <linux/pci.h>
42
#include <linux/kernel.h>
43
#include <linux/stddef.h>
44
#include <linux/sched.h>
45
#include <linux/ioport.h>
46
#include <linux/i2c.h>
47
#include <linux/init.h>
48
#include <asm/io.h>
49
 
50
/* AMD756 SMBus address offsets */
51
#define SMB_ADDR_OFFSET         0xE0
52
#define SMB_IOSIZE              16
53
#define SMB_GLOBAL_STATUS       (0x0 + amd756_ioport)
54
#define SMB_GLOBAL_ENABLE       (0x2 + amd756_ioport)
55
#define SMB_HOST_ADDRESS        (0x4 + amd756_ioport)
56
#define SMB_HOST_DATA           (0x6 + amd756_ioport)
57
#define SMB_HOST_COMMAND        (0x8 + amd756_ioport)
58
#define SMB_HOST_BLOCK_DATA     (0x9 + amd756_ioport)
59
#define SMB_HAS_DATA            (0xA + amd756_ioport)
60
#define SMB_HAS_DEVICE_ADDRESS  (0xC + amd756_ioport)
61
#define SMB_HAS_HOST_ADDRESS    (0xE + amd756_ioport)
62
#define SMB_SNOOP_ADDRESS       (0xF + amd756_ioport)
63
 
64
/* PCI Address Constants */
65
 
66
/* address of I/O space */
67
#define SMBBA           0x058           /* mh */
68
#define SMBBANFORCE     0x014
69
 
70
/* general configuration */
71
#define SMBGCFG         0x041           /* mh */
72
 
73
/* silicon revision code */
74
#define SMBREV          0x008
75
 
76
/* Other settings */
77
#define MAX_TIMEOUT     500
78
 
79
/* AMD756 constants */
80
#define AMD756_QUICK            0x00
81
#define AMD756_BYTE             0x01
82
#define AMD756_BYTE_DATA        0x02
83
#define AMD756_WORD_DATA        0x03
84
#define AMD756_PROCESS_CALL     0x04
85
#define AMD756_BLOCK_DATA       0x05
86
 
87
 
88
static unsigned short amd756_ioport = 0;
89
 
90
/*
91
  SMBUS event = I/O 28-29 bit 11
92
     see E0 for the status bits and enabled in E2
93
 
94
*/
95
#define GS_ABRT_STS     (1 << 0)
96
#define GS_COL_STS      (1 << 1)
97
#define GS_PRERR_STS    (1 << 2)
98
#define GS_HST_STS      (1 << 3)
99
#define GS_HCYC_STS     (1 << 4)
100
#define GS_TO_STS       (1 << 5)
101
#define GS_SMB_STS      (1 << 11)
102
 
103
#define GS_CLEAR_STS    (GS_ABRT_STS | GS_COL_STS | GS_PRERR_STS | \
104
                         GS_HCYC_STS | GS_TO_STS )
105
 
106
#define GE_CYC_TYPE_MASK        (7)
107
#define GE_HOST_STC             (1 << 3)
108
#define GE_ABORT                (1 << 5)
109
 
110
 
111
static int amd756_transaction(struct i2c_adapter *adap)
112
{
113
        int temp;
114
        int result = 0;
115
        int timeout = 0;
116
 
117
        dev_dbg(&adap->dev, ": Transaction (pre): GS=%04x, GE=%04x, ADD=%04x, "
118
                "DAT=%04x\n", inw_p(SMB_GLOBAL_STATUS),
119
                inw_p(SMB_GLOBAL_ENABLE), inw_p(SMB_HOST_ADDRESS),
120
                inb_p(SMB_HOST_DATA));
121
 
122
        /* Make sure the SMBus host is ready to start transmitting */
123
        if ((temp = inw_p(SMB_GLOBAL_STATUS)) & (GS_HST_STS | GS_SMB_STS)) {
124
                dev_dbg(&adap->dev, ": SMBus busy (%04x). Waiting... \n", temp);
125
                do {
126
                        i2c_delay(1);
127
                        temp = inw_p(SMB_GLOBAL_STATUS);
128
                } while ((temp & (GS_HST_STS | GS_SMB_STS)) &&
129
                         (timeout++ < MAX_TIMEOUT));
130
                /* If the SMBus is still busy, we give up */
131
                if (timeout >= MAX_TIMEOUT) {
132
                        dev_dbg(&adap->dev, ": Busy wait timeout (%04x)\n", temp);
133
                        goto abort;
134
                }
135
                timeout = 0;
136
        }
137
 
138
        /* start the transaction by setting the start bit */
139
        outw_p(inw(SMB_GLOBAL_ENABLE) | GE_HOST_STC, SMB_GLOBAL_ENABLE);
140
 
141
        /* We will always wait for a fraction of a second! */
142
        do {
143
                i2c_delay(1);
144
                temp = inw_p(SMB_GLOBAL_STATUS);
145
        } while ((temp & GS_HST_STS) && (timeout++ < MAX_TIMEOUT));
146
 
147
        /* If the SMBus is still busy, we give up */
148
        if (timeout >= MAX_TIMEOUT) {
149
                dev_dbg(&adap->dev, ": Completion timeout!\n");
150
                goto abort;
151
        }
152
 
153
        if (temp & GS_PRERR_STS) {
154
                result = -1;
155
                dev_dbg(&adap->dev, ": SMBus Protocol error (no response)!\n");
156
        }
157
 
158
        if (temp & GS_COL_STS) {
159
                result = -1;
160
                dev_warn(&adap->dev, " SMBus collision!\n");
161
        }
162
 
163
        if (temp & GS_TO_STS) {
164
                result = -1;
165
                dev_dbg(&adap->dev, ": SMBus protocol timeout!\n");
166
        }
167
 
168
        if (temp & GS_HCYC_STS)
169
                dev_dbg(&adap->dev, " SMBus protocol success!\n");
170
 
171
        outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
172
 
173
#ifdef DEBUG
174
        if (((temp = inw_p(SMB_GLOBAL_STATUS)) & GS_CLEAR_STS) != 0x00) {
175
                dev_dbg(&adap->dev,
176
                        ": Failed reset at end of transaction (%04x)\n", temp);
177
        }
178
#endif
179
 
180
        dev_dbg(&adap->dev,
181
                ": Transaction (post): GS=%04x, GE=%04x, ADD=%04x, DAT=%04x\n",
182
                inw_p(SMB_GLOBAL_STATUS), inw_p(SMB_GLOBAL_ENABLE),
183
                inw_p(SMB_HOST_ADDRESS), inb_p(SMB_HOST_DATA));
184
 
185
        return result;
186
 
187
 abort:
188
        dev_warn(&adap->dev, ": Sending abort.\n");
189
        outw_p(inw(SMB_GLOBAL_ENABLE) | GE_ABORT, SMB_GLOBAL_ENABLE);
190
        i2c_delay(100);
191
        outw_p(GS_CLEAR_STS, SMB_GLOBAL_STATUS);
192
        return -1;
193
}
194
 
195
/* Return -1 on error. */
196
static s32 amd756_access(struct i2c_adapter * adap, u16 addr,
197
                  unsigned short flags, char read_write,
198
                  u8 command, int size, union i2c_smbus_data * data)
199
{
200
        int i, len;
201
 
202
        /** TODO: Should I supporte the 10-bit transfers? */
203
        switch (size) {
204
        case I2C_SMBUS_PROC_CALL:
205
                dev_dbg(&adap->dev, ": I2C_SMBUS_PROC_CALL not supported!\n");
206
                /* TODO: Well... It is supported, I'm just not sure what to do here... */
207
                return -1;
208
        case I2C_SMBUS_QUICK:
209
                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
210
                       SMB_HOST_ADDRESS);
211
                size = AMD756_QUICK;
212
                break;
213
        case I2C_SMBUS_BYTE:
214
                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
215
                       SMB_HOST_ADDRESS);
216
                /* TODO: Why only during write? */
217
                if (read_write == I2C_SMBUS_WRITE)
218
                        outb_p(command, SMB_HOST_COMMAND);
219
                size = AMD756_BYTE;
220
                break;
221
        case I2C_SMBUS_BYTE_DATA:
222
                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
223
                       SMB_HOST_ADDRESS);
224
                outb_p(command, SMB_HOST_COMMAND);
225
                if (read_write == I2C_SMBUS_WRITE)
226
                        outw_p(data->byte, SMB_HOST_DATA);
227
                size = AMD756_BYTE_DATA;
228
                break;
229
        case I2C_SMBUS_WORD_DATA:
230
                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
231
                       SMB_HOST_ADDRESS);
232
                outb_p(command, SMB_HOST_COMMAND);
233
                if (read_write == I2C_SMBUS_WRITE)
234
                        outw_p(data->word, SMB_HOST_DATA);      /* TODO: endian???? */
235
                size = AMD756_WORD_DATA;
236
                break;
237
        case I2C_SMBUS_BLOCK_DATA:
238
                outw_p(((addr & 0x7f) << 1) | (read_write & 0x01),
239
                       SMB_HOST_ADDRESS);
240
                outb_p(command, SMB_HOST_COMMAND);
241
                if (read_write == I2C_SMBUS_WRITE) {
242
                        len = data->block[0];
243
                        if (len < 0)
244
                                len = 0;
245
                        if (len > 32)
246
                                len = 32;
247
                        outw_p(len, SMB_HOST_DATA);
248
                        /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
249
                        for (i = 1; i <= len; i++)
250
                                outb_p(data->block[i],
251
                                       SMB_HOST_BLOCK_DATA);
252
                }
253
                size = AMD756_BLOCK_DATA;
254
                break;
255
        }
256
 
257
        /* How about enabling interrupts... */
258
        outw_p(size & GE_CYC_TYPE_MASK, SMB_GLOBAL_ENABLE);
259
 
260
        if (amd756_transaction(adap))   /* Error in transaction */
261
                return -1;
262
 
263
        if ((read_write == I2C_SMBUS_WRITE) || (size == AMD756_QUICK))
264
                return 0;
265
 
266
 
267
        switch (size) {
268
        case AMD756_BYTE:
269
                data->byte = inw_p(SMB_HOST_DATA);
270
                break;
271
        case AMD756_BYTE_DATA:
272
                data->byte = inw_p(SMB_HOST_DATA);
273
                break;
274
        case AMD756_WORD_DATA:
275
                data->word = inw_p(SMB_HOST_DATA);      /* TODO: endian???? */
276
                break;
277
        case AMD756_BLOCK_DATA:
278
                data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f;
279
                if(data->block[0] > 32)
280
                        data->block[0] = 32;
281
                /* i = inw_p(SMBHSTCNT); Reset SMBBLKDAT */
282
                for (i = 1; i <= data->block[0]; i++)
283
                        data->block[i] = inb_p(SMB_HOST_BLOCK_DATA);
284
                break;
285
        }
286
 
287
        return 0;
288
}
289
 
290
static u32 amd756_func(struct i2c_adapter *adapter)
291
{
292
        return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
293
            I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
294
            I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
295
}
296
 
297
static struct i2c_algorithm smbus_algorithm = {
298
        .name           = "Non-I2C SMBus adapter",
299
        .id             = I2C_ALGO_SMBUS,
300
        .smbus_xfer     = amd756_access,
301
        .functionality  = amd756_func,
302
};
303
 
304
static struct i2c_adapter amd756_adapter = {
305
        .owner          = THIS_MODULE,
306
        .class          = I2C_ADAP_CLASS_SMBUS,
307
        .algo           = &smbus_algorithm,
308
        .name           = "unset",
309
};
310
 
311
enum chiptype { AMD756, AMD766, AMD768, NFORCE };
312
 
313
static struct pci_device_id amd756_ids[] = {
314
        {PCI_VENDOR_ID_AMD, 0x740B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD756 },
315
        {PCI_VENDOR_ID_AMD, 0x7413, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD766 },
316
        {PCI_VENDOR_ID_AMD, 0x7443, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768 },
317
        {PCI_VENDOR_ID_NVIDIA, 0x01B4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE },
318
        { 0, }
319
};
320
 
321
static int __devinit amd756_probe(struct pci_dev *pdev,
322
                                  const struct pci_device_id *id)
323
{
324
        int nforce = (id->driver_data == NFORCE), error;
325
        u8 temp;
326
 
327
        if (amd756_ioport) {
328
                dev_err(&pdev->dev, ": Only one device supported. "
329
                       "(you have a strange motherboard, btw..)\n");
330
                return -ENODEV;
331
        }
332
 
333
        if (nforce) {
334
                if (PCI_FUNC(pdev->devfn) != 1)
335
                        return -ENODEV;
336
 
337
                pci_read_config_word(pdev, SMBBANFORCE, &amd756_ioport);
338
                amd756_ioport &= 0xfffc;
339
        } else { /* amd */
340
                if (PCI_FUNC(pdev->devfn) != 3)
341
                        return -ENODEV;
342
 
343
                pci_read_config_byte(pdev, SMBGCFG, &temp);
344
                if ((temp & 128) == 0) {
345
                        dev_err(&pdev->dev,
346
                                ": Error: SMBus controller I/O not enabled!\n");
347
                        return -ENODEV;
348
                }
349
 
350
                /* Determine the address of the SMBus areas */
351
                /* Technically it is a dword but... */
352
                pci_read_config_word(pdev, SMBBA, &amd756_ioport);
353
                amd756_ioport &= 0xff00;
354
                amd756_ioport += SMB_ADDR_OFFSET;
355
        }
356
 
357
        if (!request_region(amd756_ioport, SMB_IOSIZE, "amd756-smbus")) {
358
                dev_err(&pdev->dev, ": SMB region 0x%x already in use!\n",
359
                        amd756_ioport);
360
                return -ENODEV;
361
        }
362
 
363
        pci_read_config_byte(pdev, SMBREV, &temp);
364
        dev_dbg(&pdev->dev, ": SMBREV = 0x%X\n", temp);
365
        dev_dbg(&pdev->dev, ": AMD756_smba = 0x%X\n", amd756_ioport);
366
 
367
        /* set up the driverfs linkage to our parent device */
368
        amd756_adapter.dev.parent = &pdev->dev;
369
 
370
        snprintf(amd756_adapter.name, I2C_NAME_SIZE,
371
                "SMBus AMD75x adapter at %04x", amd756_ioport);
372
 
373
        error = i2c_add_adapter(&amd756_adapter);
374
        if (error) {
375
                dev_err(&pdev->dev,
376
                        ": Adapter registration failed, module not inserted.\n");
377
                goto out_err;
378
        }
379
 
380
        return 0;
381
 
382
 out_err:
383
        release_region(amd756_ioport, SMB_IOSIZE);
384
        return error;
385
}
386
 
387
static void __devexit amd756_remove(struct pci_dev *dev)
388
{
389
        i2c_del_adapter(&amd756_adapter);
390
        release_region(amd756_ioport, SMB_IOSIZE);
391
}
392
 
393
static struct pci_driver amd756_driver = {
394
        .name           = "amd75x smbus",
395
        .id_table       = amd756_ids,
396
        .probe          = amd756_probe,
397
        .remove         = __devexit_p(amd756_remove),
398
};
399
 
400
static int __init amd756_init(void)
401
{
402
        return pci_module_init(&amd756_driver);
403
}
404
 
405
static void __exit amd756_exit(void)
406
{
407
        pci_unregister_driver(&amd756_driver);
408
}
409
 
410
MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>");
411
MODULE_DESCRIPTION("AMD756/766/768/nVidia nForce SMBus driver");
412
MODULE_LICENSE("GPL");
413
 
414
module_init(amd756_init)
415
module_exit(amd756_exit)