1 #define SMBUS_IO_BASE 0x5000
12 #define SMBTRNSADD 0x9
13 #define SMBSLVDATA 0xa
14 #define SMLINK_PIN_CTL 0xe
15 #define SMBUS_PIN_CTL 0xf
17 /* Define register settings */
18 #define HOST_RESET 0xff
19 #define DIMM_BASE 0xa0 // 1010000 is base for DIMM in SMBus
20 #define READ_CMD 0x01 // 1 in the 0 bit of SMBHSTADD states to READ
23 #define SMBUS_TIMEOUT (100*1000*10)
25 static void enable_smbus(void)
29 /* Power management controller */
30 dev = pci_locate_device(PCI_ID(0x1106, 0x8235), 0);
32 if (dev == PCI_DEV_INVALID) {
33 die("SMBUS controller not found\n");
35 // set IO base address to SMBUS_IO_BASE
36 pci_write_config32(dev, 0x90, SMBUS_IO_BASE | 1);
39 c = pci_read_config8(dev, 0xd2);
41 pci_write_config8(dev, 0xd2, c);
43 /* make it work for I/O ...
45 dev = pci_locate_device(PCI_ID(0x1106, 0x8231), 0);
46 c = pci_read_config8(dev, 4);
48 pci_write_config8(dev, 4, c);
50 print_debug(" is the comm register\n");
52 print_debug("SMBus controller enabled\n");
56 static inline void smbus_delay(void)
61 static int smbus_wait_until_active(void)
64 loops = SMBUS_TIMEOUT;
68 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
73 return loops ? 0 : -4;
76 static int smbus_wait_until_ready(void)
79 loops = SMBUS_TIMEOUT;
83 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
87 if (loops == (SMBUS_TIMEOUT / 2)) {
88 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
91 return loops ? 0 : -2;
94 static int smbus_wait_until_done(void)
97 loops = SMBUS_TIMEOUT;
102 val = inb(SMBUS_IO_BASE + SMBHSTSTAT);
103 if ((val & 1) == 0) {
107 return loops ? 0 : -3;
111 void smbus_reset(void)
113 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
114 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
115 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
116 outb(HOST_RESET, SMBUS_IO_BASE + SMBHSTSTAT);
118 smbus_wait_until_ready();
119 print_debug("After reset status ");
120 print_debug_hex8(inb(SMBUS_IO_BASE + SMBHSTSTAT));
125 #if CONFIG_DEBUG_SMBUS
126 static void smbus_print_error(unsigned char host_status_register)
129 print_err("smbus_error: ");
130 print_err_hex8(host_status_register);
132 if (host_status_register & (1 << 4)) {
133 print_err("Interrup/SMI# was Failed Bus Transaction\n");
135 if (host_status_register & (1 << 3)) {
136 print_err("Bus Error\n");
138 if (host_status_register & (1 << 2)) {
139 print_err("Device Error\n");
141 if (host_status_register & (1 << 1)) {
142 print_err("Interrupt/SMI# was Successful Completion\n");
144 if (host_status_register & (1 << 0)) {
145 print_err("Host Busy\n");
151 * Copied from intel/i82801dbm early smbus code - suggested by rgm.
152 * Modifications/check against i2c-viapro driver code from linux-2.4.22
153 * and VT8231 Reference Docs - mw.
155 static int smbus_read_byte(unsigned device, unsigned address)
157 unsigned char global_status_register;
160 if (smbus_wait_until_ready() < 0) {
161 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
162 if (smbus_wait_until_ready() < 0) {
167 /* setup transaction */
168 /* disable interrupts */
169 outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xfe, SMBUS_IO_BASE + SMBHSTCTL);
170 /* set the device I'm talking too */
171 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
172 /* set the command/address... */
173 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
174 /* set up for a byte data read */
175 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xe3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
177 /* clear any lingering errors, so the transaction will run */
178 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
180 /* clear the data byte... */
181 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
183 /* start a byte read, with interrupts disabled */
184 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
185 /* poll for it to start */
186 if (smbus_wait_until_active() < 0) {
190 /* poll for transaction completion */
191 if (smbus_wait_until_done() < 0) {
195 /* Ignore the Host Busy & Command Complete ? */
196 global_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT) & ~((1 << 1) | (1 << 0));
198 /* read results of transaction */
199 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
201 if (global_status_register != 0) {
208 /* SMBus routines borrowed from VIA's Trident Driver */
209 /* this works, so I am not going to touch it for now -- rgm */
210 static unsigned char smbus_read_byte(unsigned char devAdr, unsigned char bIndex)
214 unsigned char sts = 0;
216 /* clear host status */
217 outb(0xff, SMBUS_IO_BASE);
219 /* check SMBUS ready */
220 for (i = 0; i < SMBUS_TIMEOUT; i++)
221 if ((inb(SMBUS_IO_BASE) & 0x01) == 0)
224 /* set host command */
225 outb(bIndex, SMBUS_IO_BASE + 3);
227 /* set slave address */
228 outb(devAdr | 0x01, SMBUS_IO_BASE + 4);
231 outb(0x48, SMBUS_IO_BASE + 2);
233 /* SMBUS Wait Ready */
234 for (i = 0; i < SMBUS_TIMEOUT; i++)
235 if (((sts = inb(SMBUS_IO_BASE)) & 0x01) == 0)
237 if ((sts & ~3) != 0) {
238 smbus_print_error(sts);
241 bData = inb(SMBUS_IO_BASE + 5);
247 /* for reference, here is the fancier version which we will use at some
251 int smbus_read_byte(unsigned device, unsigned address, unsigned char *result)
253 unsigned char host_status_register;
258 smbus_wait_until_ready();
260 /* setup transaction */
261 /* disable interrupts */
262 outb(inb(SMBUS_IO_BASE + SMBHSTCTL) & (~1), SMBUS_IO_BASE + SMBHSTCTL);
263 /* set the device I'm talking too */
264 outb(((device & 0x7f) << 1) | 1, SMBUS_IO_BASE + SMBXMITADD);
265 /* set the command/address... */
266 outb(address & 0xFF, SMBUS_IO_BASE + SMBHSTCMD);
267 /* set up for a byte data read */
268 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) & 0xE3) | (0x2 << 2), SMBUS_IO_BASE + SMBHSTCTL);
270 /* clear any lingering errors, so the transaction will run */
271 outb(inb(SMBUS_IO_BASE + SMBHSTSTAT), SMBUS_IO_BASE + SMBHSTSTAT);
273 /* clear the data byte... */
274 outb(0, SMBUS_IO_BASE + SMBHSTDAT0);
276 /* start the command */
277 outb((inb(SMBUS_IO_BASE + SMBHSTCTL) | 0x40), SMBUS_IO_BASE + SMBHSTCTL);
279 /* poll for transaction completion */
280 smbus_wait_until_done();
282 host_status_register = inb(SMBUS_IO_BASE + SMBHSTSTAT);
284 /* Ignore the In Use Status... */
285 host_status_register &= ~(1 << 6);
287 /* read results of transaction */
288 byte = inb(SMBUS_IO_BASE + SMBHSTDAT0);
289 smbus_print_error(byte);
292 return host_status_register != 0x02;