| #include <device/smbus_def.h> |
| #include "i82371eb.h" |
| |
| #define SMBHST_STATUS 0x0 |
| #define SMBHST_CTL 0x2 |
| #define SMBHST_CMD 0x3 |
| #define SMBHST_ADDR 0x4 |
| #define SMBHST_DAT 0x5 |
| |
| #define SMBUS_TIMEOUT (100*1000*10) |
| #define SMBUS_STATUS_MASK 0x1e |
| #define SMBUS_ERROR_FLAG (1<<2) |
| |
| int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address); |
| |
| static inline void smbus_delay(void) |
| { |
| outb(0x80, 0x80); |
| outb(0x80, 0x80); |
| outb(0x80, 0x80); |
| outb(0x80, 0x80); |
| outb(0x80, 0x80); |
| outb(0x80, 0x80); |
| } |
| |
| static int smbus_wait_until_ready(unsigned smbus_io_base) |
| { |
| unsigned long loops; |
| loops = SMBUS_TIMEOUT; |
| do { |
| unsigned char val; |
| smbus_delay(); |
| val = inb(smbus_io_base + SMBHST_STATUS); |
| if ((val & 0x1) == 0) { |
| break; |
| } |
| #if 0 |
| if(loops == (SMBUS_TIMEOUT / 2)) { |
| outw(inw(smbus_io_base + SMBHST_STATUS), |
| smbus_io_base + SMBHST_STATUS); |
| } |
| #endif |
| } while(--loops); |
| return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT; |
| } |
| |
| static int smbus_wait_until_done(unsigned smbus_io_base) |
| { |
| unsigned long loops; |
| loops = SMBUS_TIMEOUT; |
| do { |
| unsigned short val; |
| smbus_delay(); |
| |
| val = inb(smbus_io_base + SMBHST_STATUS); |
| // Make sure the command is done |
| if ((val & 0x1) != 0) { |
| continue; |
| } |
| // Don't break out until one of the interrupt |
| // flags is set. |
| if (val & 0xfe) { |
| break; |
| } |
| } while(--loops); |
| return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT; |
| } |
| |
| int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address) |
| { |
| unsigned status_register; |
| unsigned byte; |
| |
| if (smbus_wait_until_ready(smbus_io_base) < 0) { |
| return SMBUS_WAIT_UNTIL_READY_TIMEOUT; |
| } |
| |
| /* setup transaction */ |
| |
| /* clear any lingering errors, so the transaction will run */ |
| outb(0x1e, smbus_io_base + SMBHST_STATUS); |
| |
| /* set the device I'm talking too */ |
| outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR); |
| |
| /* set the command/address... */ |
| outb(address & 0xff, smbus_io_base + SMBHST_CMD); |
| |
| /* clear the data word...*/ |
| outb(0, smbus_io_base + SMBHST_DAT); |
| |
| /* start a byte read with interrupts disabled */ |
| outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL); |
| |
| /* poll for transaction completion */ |
| if (smbus_wait_until_done(smbus_io_base) < 0) { |
| return SMBUS_WAIT_UNTIL_DONE_TIMEOUT; |
| } |
| |
| status_register = inw(smbus_io_base + SMBHST_STATUS); |
| |
| /* read results of transaction */ |
| byte = inw(smbus_io_base + SMBHST_DAT) & 0xff; |
| |
| if (status_register & 0x04) { |
| #if 0 |
| printk(BIOS_DEBUG, "Read fail %04x\n", status_register); |
| #endif |
| return SMBUS_ERROR; |
| } |
| return byte; |
| } |