blob: fd0221793e75eb3cf423151bebba763ac98fdc5b [file] [log] [blame]
Richard Smithcb8eab42006-07-24 04:25:47 +00001#include <device/smbus_def.h>
Uwe Hermann4028ce72010-12-07 19:16:07 +00002#include "i82371eb.h"
Richard Smithcb8eab42006-07-24 04:25:47 +00003
Richard Smithd7088c42006-07-30 00:23:20 +00004#define SMBHST_STATUS 0x0
5#define SMBHST_CTL 0x2
6#define SMBHST_CMD 0x3
7#define SMBHST_ADDR 0x4
8#define SMBHST_DAT 0x5
Richard Smithcb8eab42006-07-24 04:25:47 +00009
10#define SMBUS_TIMEOUT (100*1000*10)
11#define SMBUS_STATUS_MASK 0x1e
Richard Smithd7088c42006-07-30 00:23:20 +000012#define SMBUS_ERROR_FLAG (1<<2)
Richard Smithcb8eab42006-07-24 04:25:47 +000013
Uwe Hermann115c5b92010-10-09 17:00:18 +000014int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address);
15
Richard Smithcb8eab42006-07-24 04:25:47 +000016static inline void smbus_delay(void)
17{
18 outb(0x80, 0x80);
19 outb(0x80, 0x80);
20 outb(0x80, 0x80);
21 outb(0x80, 0x80);
22 outb(0x80, 0x80);
23 outb(0x80, 0x80);
24}
25
26static int smbus_wait_until_ready(unsigned smbus_io_base)
27{
28 unsigned long loops;
29 loops = SMBUS_TIMEOUT;
30 do {
31 unsigned char val;
32 smbus_delay();
Richard Smithd7088c42006-07-30 00:23:20 +000033 val = inb(smbus_io_base + SMBHST_STATUS);
Richard Smithcb8eab42006-07-24 04:25:47 +000034 if ((val & 0x1) == 0) {
35 break;
36 }
Stefan Reinauer14e22772010-04-27 06:56:47 +000037#if 0
Richard Smithcb8eab42006-07-24 04:25:47 +000038 if(loops == (SMBUS_TIMEOUT / 2)) {
Stefan Reinauer14e22772010-04-27 06:56:47 +000039 outw(inw(smbus_io_base + SMBHST_STATUS),
Richard Smithd7088c42006-07-30 00:23:20 +000040 smbus_io_base + SMBHST_STATUS);
Richard Smithcb8eab42006-07-24 04:25:47 +000041 }
Richard Smithd7088c42006-07-30 00:23:20 +000042#endif
Richard Smithcb8eab42006-07-24 04:25:47 +000043 } while(--loops);
44 return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
45}
46
47static int smbus_wait_until_done(unsigned smbus_io_base)
48{
49 unsigned long loops;
50 loops = SMBUS_TIMEOUT;
51 do {
52 unsigned short val;
53 smbus_delay();
Stefan Reinauer14e22772010-04-27 06:56:47 +000054
Richard Smithd7088c42006-07-30 00:23:20 +000055 val = inb(smbus_io_base + SMBHST_STATUS);
Richard Smithcb8eab42006-07-24 04:25:47 +000056 // Make sure the command is done
Stefan Reinauer14e22772010-04-27 06:56:47 +000057 if ((val & 0x1) != 0) {
Richard Smithcb8eab42006-07-24 04:25:47 +000058 continue;
59 }
60 // Don't break out until one of the interrupt
61 // flags is set.
62 if (val & 0xfe) {
63 break;
64 }
65 } while(--loops);
66 return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
67}
68
Uwe Hermann115c5b92010-10-09 17:00:18 +000069int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
Richard Smithcb8eab42006-07-24 04:25:47 +000070{
Richard Smithd7088c42006-07-30 00:23:20 +000071 unsigned status_register;
Richard Smithcb8eab42006-07-24 04:25:47 +000072 unsigned byte;
73
74 if (smbus_wait_until_ready(smbus_io_base) < 0) {
75 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
76 }
Stefan Reinauer14e22772010-04-27 06:56:47 +000077
Richard Smithcb8eab42006-07-24 04:25:47 +000078 /* setup transaction */
79
80 /* clear any lingering errors, so the transaction will run */
Richard Smithd7088c42006-07-30 00:23:20 +000081 outb(0x1e, smbus_io_base + SMBHST_STATUS);
Richard Smithcb8eab42006-07-24 04:25:47 +000082
83 /* set the device I'm talking too */
Richard Smithd7088c42006-07-30 00:23:20 +000084 outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR);
85
Richard Smithcb8eab42006-07-24 04:25:47 +000086 /* set the command/address... */
Richard Smithd7088c42006-07-30 00:23:20 +000087 outb(address & 0xff, smbus_io_base + SMBHST_CMD);
Richard Smithcb8eab42006-07-24 04:25:47 +000088
89 /* clear the data word...*/
Richard Smithd7088c42006-07-30 00:23:20 +000090 outb(0, smbus_io_base + SMBHST_DAT);
Richard Smithcb8eab42006-07-24 04:25:47 +000091
92 /* start a byte read with interrupts disabled */
Richard Smithd7088c42006-07-30 00:23:20 +000093 outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL);
Richard Smithcb8eab42006-07-24 04:25:47 +000094
95 /* poll for transaction completion */
96 if (smbus_wait_until_done(smbus_io_base) < 0) {
97 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
98 }
99
Richard Smithd7088c42006-07-30 00:23:20 +0000100 status_register = inw(smbus_io_base + SMBHST_STATUS);
Richard Smithcb8eab42006-07-24 04:25:47 +0000101
102 /* read results of transaction */
Richard Smithd7088c42006-07-30 00:23:20 +0000103 byte = inw(smbus_io_base + SMBHST_DAT) & 0xff;
Richard Smithcb8eab42006-07-24 04:25:47 +0000104
Richard Smithd7088c42006-07-30 00:23:20 +0000105 if (status_register & 0x04) {
106#if 0
Stefan Reinauer5ab52dd2015-01-05 13:01:01 -0800107 printk(BIOS_DEBUG, "Read fail %04x\n", status_register);
Richard Smithd7088c42006-07-30 00:23:20 +0000108#endif
Richard Smithcb8eab42006-07-24 04:25:47 +0000109 return SMBUS_ERROR;
110 }
111 return byte;
112}