1 #include <device/smbus_def.h>
3 #define SMBGSTATUS 0xe0
5 #define SMBHSTADDR 0xe4
8 #define SMBHSTFIFO 0xe9
10 #define SMBUS_TIMEOUT (100*1000*10)
11 #define SMBUS_STATUS_MASK 0xfbff
13 static inline void smbus_delay(void)
18 static int smbus_wait_until_ready(unsigned smbus_io_base)
21 loops = SMBUS_TIMEOUT;
25 val = inw(smbus_io_base + SMBGSTATUS);
26 if ((val & 0x800) == 0) {
29 if(loops == (SMBUS_TIMEOUT / 2)) {
30 outw(inw(smbus_io_base + SMBGSTATUS),
31 smbus_io_base + SMBGSTATUS);
34 return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
37 static int smbus_wait_until_done(unsigned smbus_io_base)
40 loops = SMBUS_TIMEOUT;
45 val = inw(smbus_io_base + SMBGSTATUS);
46 if (((val & 0x8) == 0) | ((val & 0x0037) != 0)) {
50 return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
53 static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
55 unsigned global_status_register;
58 if (smbus_wait_until_ready(smbus_io_base) < 0) {
59 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
62 /* setup transaction */
63 /* disable interrupts */
64 outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
65 /* set the device I'm talking too */
66 outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
67 /* set the command/address... */
68 outb(0, smbus_io_base + SMBHSTCMD);
69 /* set up for a send byte */
70 outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
72 /* clear any lingering errors, so the transaction will run */
73 /* Do I need to write the bits to a 1 to clear an error? */
74 outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
76 /* set the data word...*/
77 outw(0, smbus_io_base + SMBHSTDAT);
79 /* start the command */
80 outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
83 /* poll for transaction completion */
84 if (smbus_wait_until_done(smbus_io_base) < 0) {
85 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
88 global_status_register = inw(smbus_io_base + SMBGSTATUS);
90 /* read results of transaction */
91 byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
93 if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
99 static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value)
101 unsigned global_status_register;
103 if (smbus_wait_until_ready(smbus_io_base) < 0) {
104 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
107 /* setup transaction */
108 /* disable interrupts */
109 outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
110 /* set the device I'm talking too */
111 outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
112 /* set the command/address... */
113 outb(0, smbus_io_base + SMBHSTCMD);
114 /* set up for a send byte */
115 outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x1), smbus_io_base + SMBGCTL);
117 /* clear any lingering errors, so the transaction will run */
118 /* Do I need to write the bits to a 1 to clear an error? */
119 outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
121 /* set the data word...*/
122 outw(value, smbus_io_base + SMBHSTDAT);
124 /* start the command */
125 outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
128 /* poll for transaction completion */
129 if (smbus_wait_until_done(smbus_io_base) < 0) {
130 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
132 global_status_register = inw(smbus_io_base + SMBGSTATUS);
134 if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
141 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
143 unsigned global_status_register;
146 if (smbus_wait_until_ready(smbus_io_base) < 0) {
147 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
150 /* setup transaction */
151 /* disable interrupts */
152 outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
153 /* set the device I'm talking too */
154 outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHSTADDR);
155 /* set the command/address... */
156 outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
157 /* set up for a byte data read */
158 outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL);
160 /* clear any lingering errors, so the transaction will run */
161 /* Do I need to write the bits to a 1 to clear an error? */
162 outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
164 /* clear the data word...*/
165 outw(0, smbus_io_base + SMBHSTDAT);
167 /* start the command */
168 outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
171 /* poll for transaction completion */
172 if (smbus_wait_until_done(smbus_io_base) < 0) {
173 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
176 global_status_register = inw(smbus_io_base + SMBGSTATUS);
178 /* read results of transaction */
179 byte = inw(smbus_io_base + SMBHSTDAT) & 0xff;
181 if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
187 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
189 unsigned global_status_register;
191 if (smbus_wait_until_ready(smbus_io_base) < 0) {
192 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
195 /* setup transaction */
196 /* disable interrupts */
197 outw(inw(smbus_io_base + SMBGCTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBGCTL);
198 /* set the device I'm talking too */
199 outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHSTADDR);
200 outb(address & 0xFF, smbus_io_base + SMBHSTCMD);
201 /* set up for a byte data write */ /* FIXME */
202 outw((inw(smbus_io_base + SMBGCTL) & ~7) | (0x2), smbus_io_base + SMBGCTL);
203 /* clear any lingering errors, so the transaction will run */
204 /* Do I need to write the bits to a 1 to clear an error? */
205 outw(inw(smbus_io_base + SMBGSTATUS), smbus_io_base + SMBGSTATUS);
207 /* write the data word...*/
208 outw(val, smbus_io_base + SMBHSTDAT);
210 /* start the command */
211 outw((inw(smbus_io_base + SMBGCTL) | (1 << 3)), smbus_io_base + SMBGCTL);
213 /* poll for transaction completion */
214 if (smbus_wait_until_done(smbus_io_base) < 0) {
215 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
217 global_status_register = inw(smbus_io_base + SMBGSTATUS);
219 if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {