]>
Commit | Line | Data |
---|---|---|
fc0bdd99 IY |
1 | /* |
2 | * PC SMBus implementation | |
3 | * splitted from acpi.c | |
4 | * | |
5 | * Copyright (c) 2006 Fabrice Bellard | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License version 2 as published by the Free Software Foundation. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
1012e960 BS |
17 | * License along with this library; if not, see |
18 | * <http://www.gnu.org/licenses/>. | |
fc0bdd99 IY |
19 | */ |
20 | #include "hw.h" | |
21 | #include "pc.h" | |
22 | #include "pm_smbus.h" | |
fc0bdd99 | 23 | #include "smbus.h" |
fc0bdd99 IY |
24 | |
25 | /* no save/load? */ | |
26 | ||
27 | #define SMBHSTSTS 0x00 | |
28 | #define SMBHSTCNT 0x02 | |
29 | #define SMBHSTCMD 0x03 | |
30 | #define SMBHSTADD 0x04 | |
31 | #define SMBHSTDAT0 0x05 | |
32 | #define SMBHSTDAT1 0x06 | |
33 | #define SMBBLKDAT 0x07 | |
34 | ||
b246eebb IY |
35 | //#define DEBUG |
36 | ||
37 | #ifdef DEBUG | |
38 | # define SMBUS_DPRINTF(format, ...) printf(format, ## __VA_ARGS__) | |
39 | #else | |
40 | # define SMBUS_DPRINTF(format, ...) do { } while (0) | |
41 | #endif | |
42 | ||
43 | ||
fc0bdd99 IY |
44 | static void smb_transaction(PMSMBus *s) |
45 | { | |
46 | uint8_t prot = (s->smb_ctl >> 2) & 0x07; | |
47 | uint8_t read = s->smb_addr & 0x01; | |
48 | uint8_t cmd = s->smb_cmd; | |
49 | uint8_t addr = s->smb_addr >> 1; | |
50 | i2c_bus *bus = s->smbus; | |
51 | ||
b246eebb | 52 | SMBUS_DPRINTF("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot); |
fc0bdd99 IY |
53 | switch(prot) { |
54 | case 0x0: | |
55 | smbus_quick_command(bus, addr, read); | |
56 | break; | |
57 | case 0x1: | |
58 | if (read) { | |
59 | s->smb_data0 = smbus_receive_byte(bus, addr); | |
60 | } else { | |
61 | smbus_send_byte(bus, addr, cmd); | |
62 | } | |
63 | break; | |
64 | case 0x2: | |
65 | if (read) { | |
66 | s->smb_data0 = smbus_read_byte(bus, addr, cmd); | |
67 | } else { | |
68 | smbus_write_byte(bus, addr, cmd, s->smb_data0); | |
69 | } | |
70 | break; | |
71 | case 0x3: | |
72 | if (read) { | |
73 | uint16_t val; | |
74 | val = smbus_read_word(bus, addr, cmd); | |
75 | s->smb_data0 = val; | |
76 | s->smb_data1 = val >> 8; | |
77 | } else { | |
78 | smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0); | |
79 | } | |
80 | break; | |
81 | case 0x5: | |
82 | if (read) { | |
83 | s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data); | |
84 | } else { | |
85 | smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0); | |
86 | } | |
87 | break; | |
88 | default: | |
89 | goto error; | |
90 | } | |
91 | return; | |
92 | ||
93 | error: | |
94 | s->smb_stat |= 0x04; | |
95 | } | |
96 | ||
97 | void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) | |
98 | { | |
99 | PMSMBus *s = opaque; | |
100 | addr &= 0x3f; | |
b246eebb | 101 | SMBUS_DPRINTF("SMB writeb port=0x%04x val=0x%02x\n", addr, val); |
fc0bdd99 IY |
102 | switch(addr) { |
103 | case SMBHSTSTS: | |
104 | s->smb_stat = 0; | |
105 | s->smb_index = 0; | |
106 | break; | |
107 | case SMBHSTCNT: | |
108 | s->smb_ctl = val; | |
109 | if (val & 0x40) | |
110 | smb_transaction(s); | |
111 | break; | |
112 | case SMBHSTCMD: | |
113 | s->smb_cmd = val; | |
114 | break; | |
115 | case SMBHSTADD: | |
116 | s->smb_addr = val; | |
117 | break; | |
118 | case SMBHSTDAT0: | |
119 | s->smb_data0 = val; | |
120 | break; | |
121 | case SMBHSTDAT1: | |
122 | s->smb_data1 = val; | |
123 | break; | |
124 | case SMBBLKDAT: | |
125 | s->smb_data[s->smb_index++] = val; | |
126 | if (s->smb_index > 31) | |
127 | s->smb_index = 0; | |
128 | break; | |
129 | default: | |
130 | break; | |
131 | } | |
132 | } | |
133 | ||
134 | uint32_t smb_ioport_readb(void *opaque, uint32_t addr) | |
135 | { | |
136 | PMSMBus *s = opaque; | |
137 | uint32_t val; | |
138 | ||
139 | addr &= 0x3f; | |
140 | switch(addr) { | |
141 | case SMBHSTSTS: | |
142 | val = s->smb_stat; | |
143 | break; | |
144 | case SMBHSTCNT: | |
145 | s->smb_index = 0; | |
146 | val = s->smb_ctl & 0x1f; | |
147 | break; | |
148 | case SMBHSTCMD: | |
149 | val = s->smb_cmd; | |
150 | break; | |
151 | case SMBHSTADD: | |
152 | val = s->smb_addr; | |
153 | break; | |
154 | case SMBHSTDAT0: | |
155 | val = s->smb_data0; | |
156 | break; | |
157 | case SMBHSTDAT1: | |
158 | val = s->smb_data1; | |
159 | break; | |
160 | case SMBBLKDAT: | |
161 | val = s->smb_data[s->smb_index++]; | |
162 | if (s->smb_index > 31) | |
163 | s->smb_index = 0; | |
164 | break; | |
165 | default: | |
166 | val = 0; | |
167 | break; | |
168 | } | |
b246eebb | 169 | SMBUS_DPRINTF("SMB readb port=0x%04x val=0x%02x\n", addr, val); |
fc0bdd99 IY |
170 | return val; |
171 | } | |
172 | ||
173 | void pm_smbus_init(DeviceState *parent, PMSMBus *smb) | |
174 | { | |
175 | smb->smbus = i2c_init_bus(parent, "i2c"); | |
176 | } |