blob: b16679760035e95dce9a8fc44ba46b2f870458e4 [file] [log] [blame]
Yinghai Lu13f1c2a2005-07-08 02:49:49 +00001#include <device/smbus_def.h>
2
3#define SMBHSTSTAT 0x0
4#define SMBHSTCTL 0x2
5#define SMBHSTCMD 0x3
6#define SMBXMITADD 0x4
7#define SMBHSTDAT0 0x5
8#define SMBHSTDAT1 0x6
9#define SMBBLKDAT 0x7
10#define SMBTRNSADD 0x9
11#define SMBSLVDATA 0xa
12#define SMLINK_PIN_CTL 0xe
Stefan Reinauer14e22772010-04-27 06:56:47 +000013#define SMBUS_PIN_CTL 0xf
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000014
15#define SMBUS_TIMEOUT (100*1000*10)
16
17
18static void smbus_delay(void)
19{
20 outb(0x80, 0x80);
21}
22
23static int smbus_wait_until_ready(unsigned smbus_io_base)
24{
25 unsigned loops = SMBUS_TIMEOUT;
26 unsigned char byte;
27 do {
28 smbus_delay();
29 if (--loops == 0)
30 break;
31 byte = inb(smbus_io_base + SMBHSTSTAT);
32 } while(byte & 1);
33 return loops?0:-1;
34}
35
36static int smbus_wait_until_done(unsigned smbus_io_base)
37{
38 unsigned loops = SMBUS_TIMEOUT;
39 unsigned char byte;
40 do {
41 smbus_delay();
42 if (--loops == 0)
43 break;
44 byte = inb(smbus_io_base + SMBHSTSTAT);
45 } while((byte & 1) || (byte & ~((1<<6)|(1<<0))) == 0);
46 return loops?0:-1;
47}
48
Stefan Reinauer68f542c2010-03-17 02:48:24 +000049static inline int smbus_wait_until_blk_done(unsigned smbus_io_base)
Yinghai Lu13f1c2a2005-07-08 02:49:49 +000050{
51 unsigned loops = SMBUS_TIMEOUT;
52 unsigned char byte;
53 do {
54 smbus_delay();
55 if (--loops == 0)
56 break;
57 byte = inb(smbus_io_base + SMBHSTSTAT);
58 } while((byte&(1<<7)) == 0);
59 return loops?0:-1;
60}
61
62static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
63{
64 unsigned char global_status_register;
65 unsigned char byte;
66
67 if (smbus_wait_until_ready(smbus_io_base) < 0) {
68 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
69 }
70 /* setup transaction */
71 /* disable interrupts */
72 outb(inb(smbus_io_base + SMBHSTCTL) & (~1), smbus_io_base + SMBHSTCTL);
73 /* set the device I'm talking too */
74 outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBXMITADD);
75 /* set the command/address... */
76 outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
77 /* set up for a byte data read */
78 outb((inb(smbus_io_base + SMBHSTCTL) & 0xE3) | (0x2 << 2), smbus_io_base + SMBHSTCTL);
79 /* clear any lingering errors, so the transaction will run */
80 outb(inb(smbus_io_base + SMBHSTSTAT), smbus_io_base + SMBHSTSTAT);
81
82 /* clear the data byte...*/
83 outb(0, smbus_io_base + SMBHSTDAT0);
84
85 /* start the command */
86 outb((inb(smbus_io_base + SMBHSTCTL) | 0x40), smbus_io_base + SMBHSTCTL);
87
88 /* poll for transaction completion */
89 if (smbus_wait_until_done(smbus_io_base) < 0) {
90 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
91 }
92
93 global_status_register = inb(smbus_io_base + SMBHSTSTAT);
94
95 /* Ignore the In Use Status... */
96 global_status_register &= ~(3 << 5);
97
98 /* read results of transaction */
99 byte = inb(smbus_io_base + SMBHSTDAT0);
100 if (global_status_register != (1 << 1)) {
101 return SMBUS_ERROR;
102 }
103 return byte;
104}