1 #include <device/smbus_def.h>
3 #define SMBHST_STATUS 0x0
6 #define SMBHST_ADDR 0x4
9 #define SMBUS_TIMEOUT (100*1000*10)
10 #define SMBUS_STATUS_MASK 0x1e
11 #define SMBUS_ERROR_FLAG (1<<2)
13 static inline void smbus_delay(void)
23 static int smbus_wait_until_ready(unsigned smbus_io_base)
26 loops = SMBUS_TIMEOUT;
30 val = inb(smbus_io_base + SMBHST_STATUS);
31 if ((val & 0x1) == 0) {
35 if(loops == (SMBUS_TIMEOUT / 2)) {
36 outw(inw(smbus_io_base + SMBHST_STATUS),
37 smbus_io_base + SMBHST_STATUS);
41 return loops?0:SMBUS_WAIT_UNTIL_READY_TIMEOUT;
44 static int smbus_wait_until_done(unsigned smbus_io_base)
47 loops = SMBUS_TIMEOUT;
52 val = inb(smbus_io_base + SMBHST_STATUS);
53 // Make sure the command is done
54 if ((val & 0x1) != 0) {
57 // Don't break out until one of the interrupt
63 return loops?0:SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
66 static int do_smbus_recv_byte(unsigned smbus_io_base, unsigned device)
68 unsigned global_status_register;
71 if (smbus_wait_until_ready(smbus_io_base) < 0) {
72 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
75 /* setup transaction */
76 /* disable interrupts */
77 outw(inw(smbus_io_base + SMBHST_CTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBHST_CTL);
78 /* set the device I'm talking too */
79 outw(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR);
80 /* set the command/address... */
81 outb(0, smbus_io_base + SMBHST_CMD);
82 /* set up for a send byte */
83 outw((inw(smbus_io_base + SMBHST_CTL) & ~7) | (0x1), smbus_io_base + SMBHST_CTL);
85 /* clear any lingering errors, so the transaction will run */
86 /* Do I need to write the bits to a 1 to clear an error? */
87 outw(inw(smbus_io_base + SMBHST_STATUS), smbus_io_base + SMBHST_STATUS);
89 /* set the data word...*/
90 outw(0, smbus_io_base + SMBHST_DAT);
92 /* start the command */
93 outw((inw(smbus_io_base + SMBHST_CTL) | (1 << 3)), smbus_io_base + SMBHST_CTL);
96 /* poll for transaction completion */
97 if (smbus_wait_until_done(smbus_io_base) < 0) {
98 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
101 global_status_register = inw(smbus_io_base + SMBHST_STATUS);
103 /* read results of transaction */
104 byte = inb(smbus_io_base + SMBHST_DAT) & 0xff;
106 // Check for any result other than a command completion
107 if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 1)) {
113 static int do_smbus_send_byte(unsigned smbus_io_base, unsigned device, unsigned value)
115 unsigned global_status_register;
117 if (smbus_wait_until_ready(smbus_io_base) < 0) {
118 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
121 /* setup transaction */
122 /* disable interrupts */
123 outw(inw(smbus_io_base + SMBHST_CTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBHST_CTL);
124 /* set the device I'm talking too */
125 outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHST_ADDR);
126 /* set the command/address... */
127 outb(0, smbus_io_base + SMBHST_CMD);
128 /* set up for a send byte */
129 outw((inw(smbus_io_base + SMBHST_CTL) & ~7) | (0x1), smbus_io_base + SMBHST_CTL);
131 /* clear any lingering errors, so the transaction will run */
132 /* Do I need to write the bits to a 1 to clear an error? */
133 outw(inw(smbus_io_base + SMBHST_STATUS), smbus_io_base + SMBHST_STATUS);
135 /* set the data word...*/
136 outw(value, smbus_io_base + SMBHST_DAT);
138 /* start the command */
139 outw((inw(smbus_io_base + SMBHST_CTL) | (1 << 3)), smbus_io_base + SMBHST_CTL);
142 /* poll for transaction completion */
143 if (smbus_wait_until_done(smbus_io_base) < 0) {
144 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
146 global_status_register = inw(smbus_io_base + SMBHST_STATUS);
148 if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 4)) {
155 static int do_smbus_read_byte(unsigned smbus_io_base, unsigned device, unsigned address)
157 unsigned status_register;
160 if (smbus_wait_until_ready(smbus_io_base) < 0) {
161 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
164 /* setup transaction */
166 /* clear any lingering errors, so the transaction will run */
167 outb(0x1e, smbus_io_base + SMBHST_STATUS);
169 /* set the device I'm talking too */
170 outb(((device & 0x7f) << 1) | 1, smbus_io_base + SMBHST_ADDR);
172 /* set the command/address... */
173 outb(address & 0xff, smbus_io_base + SMBHST_CMD);
175 /* clear the data word...*/
176 outb(0, smbus_io_base + SMBHST_DAT);
178 /* start a byte read with interrupts disabled */
179 outb( (0x02 << 2)|(1<<6), smbus_io_base + SMBHST_CTL);
181 /* poll for transaction completion */
182 if (smbus_wait_until_done(smbus_io_base) < 0) {
183 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
186 status_register = inw(smbus_io_base + SMBHST_STATUS);
188 /* read results of transaction */
189 byte = inw(smbus_io_base + SMBHST_DAT) & 0xff;
191 if (status_register & 0x04) {
193 print_debug("Read fail ");
194 print_debug_hex16(status_register);
202 static int do_smbus_write_byte(unsigned smbus_io_base, unsigned device, unsigned address, unsigned char val)
204 unsigned global_status_register;
206 if (smbus_wait_until_ready(smbus_io_base) < 0) {
207 return SMBUS_WAIT_UNTIL_READY_TIMEOUT;
210 /* setup transaction */
211 /* disable interrupts */
212 outw(inw(smbus_io_base + SMBHST_CTL) & ~((1<<10)|(1<<9)|(1<<8)|(1<<4)), smbus_io_base + SMBHST_CTL);
213 /* set the device I'm talking too */
214 outw(((device & 0x7f) << 1) | 0, smbus_io_base + SMBHST_ADDR);
215 outb(address & 0xFF, smbus_io_base + SMBHST_CMD);
216 /* set up for a byte data write */ /* FIXME */
217 outw((inw(smbus_io_base + SMBHST_CTL) & ~7) | (0x2), smbus_io_base + SMBHST_CTL);
218 /* clear any lingering errors, so the transaction will run */
219 /* Do I need to write the bits to a 1 to clear an error? */
220 outw(inw(smbus_io_base + SMBHST_STATUS), smbus_io_base + SMBHST_STATUS);
222 /* write the data word...*/
223 outw(val, smbus_io_base + SMBHST_DAT);
225 /* start the command */
226 outw((inw(smbus_io_base + SMBHST_CTL) | (1 << 3)), smbus_io_base + SMBHST_CTL);
228 /* poll for transaction completion */
229 if (smbus_wait_until_done(smbus_io_base) < 0) {
230 return SMBUS_WAIT_UNTIL_DONE_TIMEOUT;
232 global_status_register = inw(smbus_io_base + SMBHST_STATUS);
234 if ((global_status_register & SMBUS_STATUS_MASK) != (1 << 1)) {