2 * This file is part of the coreboot project.
4 * Copyright (C) 2007 Advanced Micro Devices, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #define SMBUS_ERROR -1
23 #define SMBUS_WAIT_UNTIL_READY_TIMEOUT -2
24 #define SMBUS_WAIT_UNTIL_DONE_TIMEOUT -3
25 #define SMBUS_TIMEOUT (1000)
27 /* initialization for SMBus Controller */
28 static void cs5536_enable_smbus(void)
31 /* Set SCL freq and enable SMB controller */
32 /*outb((0x20 << 1) | SMB_CTRL2_ENABLE, smbus_io_base + SMB_CTRL2); */
33 outb((0x7F << 1) | SMB_CTRL2_ENABLE, SMBUS_IO_BASE + SMB_CTRL2);
35 /* Setup SMBus host controller address to 0xEF */
36 outb((0xEF | SMB_ADD_SAEN), SMBUS_IO_BASE + SMB_ADD);
40 static void smbus_delay(void)
45 static int smbus_wait(unsigned smbus_io_base)
47 unsigned long loops = SMBUS_TIMEOUT;
52 val = inb(smbus_io_base + SMB_STS);
53 if ((val & SMB_STS_SDAST) != 0)
55 if (val & (SMB_STS_BER | SMB_STS_NEGACK)) {
56 /*printk(BIOS_DEBUG, "SMBUS WAIT ERROR %x\n", val); */
60 return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
63 /* generate a smbus start condition */
64 static int smbus_start_condition(unsigned smbus_io_base)
68 /* issue a START condition */
69 val = inb(smbus_io_base + SMB_CTRL1);
70 outb(val | SMB_CTRL1_START, smbus_io_base + SMB_CTRL1);
72 /* check for bus conflict */
73 val = inb(smbus_io_base + SMB_STS);
74 if ((val & SMB_STS_BER) != 0)
77 return smbus_wait(smbus_io_base);
80 static int smbus_check_stop_condition(unsigned smbus_io_base)
84 loops = SMBUS_TIMEOUT;
85 /* check for SDA status */
88 val = inb(smbus_io_base + SMB_CTRL1);
89 if ((val & SMB_CTRL1_STOP) == 0) {
92 outb((0x7F << 1) | SMB_CTRL2_ENABLE, smbus_io_base + SMB_CTRL2);
94 return loops ? 0 : SMBUS_WAIT_UNTIL_READY_TIMEOUT;
97 static int smbus_stop_condition(unsigned smbus_io_base)
99 outb(SMB_CTRL1_STOP, smbus_io_base + SMB_CTRL1);
100 return smbus_wait(smbus_io_base);
103 static int smbus_ack(unsigned smbus_io_base, int state)
105 unsigned char val = inb(smbus_io_base + SMB_CTRL1);
108 outb(val | SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
110 outb(val & ~SMB_CTRL1_ACK, smbus_io_base + SMB_CTRL1);
115 static int smbus_send_slave_address(unsigned smbus_io_base,
116 unsigned char device)
120 /* send the slave address */
121 outb(device, smbus_io_base + SMB_SDA);
123 /* check for bus conflict and NACK */
124 val = inb(smbus_io_base + SMB_STS);
125 if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0)) {
126 /* printk(BIOS_DEBUG, "SEND SLAVE ERROR (%x)\n", val); */
129 return smbus_wait(smbus_io_base);
132 static int smbus_send_command(unsigned smbus_io_base, unsigned char command)
136 /* send the command */
137 outb(command, smbus_io_base + SMB_SDA);
139 /* check for bus conflict and NACK */
140 val = inb(smbus_io_base + SMB_STS);
141 if (((val & SMB_STS_BER) != 0) || ((val & SMB_STS_NEGACK) != 0))
144 return smbus_wait(smbus_io_base);
147 static unsigned char smbus_get_result(unsigned smbus_io_base)
149 return inb(smbus_io_base + SMB_SDA);
152 static unsigned char do_smbus_read_byte(unsigned smbus_io_base,
153 unsigned char device,
154 unsigned char address)
156 unsigned char error = 0;
158 if ((smbus_check_stop_condition(smbus_io_base))) {
163 if ((smbus_start_condition(smbus_io_base))) {
168 if ((smbus_send_slave_address(smbus_io_base, device))) {
173 smbus_ack(smbus_io_base, 1);
175 if ((smbus_send_command(smbus_io_base, address))) {
180 if ((smbus_start_condition(smbus_io_base))) {
185 if ((smbus_send_slave_address(smbus_io_base, device | 0x01))) {
190 if ((smbus_stop_condition(smbus_io_base))) {
195 return smbus_get_result(smbus_io_base);
198 print_debug("SMBUS READ ERROR:");
199 print_debug_hex8(error);
200 print_debug(" device:");
201 print_debug_hex8(device);
203 /* stop, clean up the error, and leave */
204 smbus_stop_condition(smbus_io_base);
205 outb(inb(smbus_io_base + SMB_STS), smbus_io_base + SMB_STS);
206 outb(0x0, smbus_io_base + SMB_STS);
210 static inline int smbus_read_byte(unsigned device, unsigned address)
212 return do_smbus_read_byte(SMBUS_IO_BASE, device, address);