root / hw / smbus.c @ fa156e51
History | View | Annotate | Download (8.1 kB)
1 | 5fafdf24 | ths | /*
|
---|---|---|---|
2 | 0ff596d0 | pbrook | * QEMU SMBus device emulation.
|
3 | 0ff596d0 | pbrook | *
|
4 | 0ff596d0 | pbrook | * Copyright (c) 2007 CodeSourcery.
|
5 | 0ff596d0 | pbrook | * Written by Paul Brook
|
6 | 0ff596d0 | pbrook | *
|
7 | 8e31bf38 | Matthew Fernandez | * This code is licensed under the LGPL.
|
8 | 0ff596d0 | pbrook | */
|
9 | 0ff596d0 | pbrook | |
10 | 0ff596d0 | pbrook | /* TODO: Implement PEC. */
|
11 | 0ff596d0 | pbrook | |
12 | 87ecb68b | pbrook | #include "hw.h" |
13 | 87ecb68b | pbrook | #include "i2c.h" |
14 | 87ecb68b | pbrook | #include "smbus.h" |
15 | 0ff596d0 | pbrook | |
16 | 0ff596d0 | pbrook | //#define DEBUG_SMBUS 1
|
17 | 0ff596d0 | pbrook | |
18 | 0ff596d0 | pbrook | #ifdef DEBUG_SMBUS
|
19 | 001faf32 | Blue Swirl | #define DPRINTF(fmt, ...) \
|
20 | 001faf32 | Blue Swirl | do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0) |
21 | 001faf32 | Blue Swirl | #define BADF(fmt, ...) \
|
22 | 001faf32 | Blue Swirl | do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) |
23 | 0ff596d0 | pbrook | #else
|
24 | 001faf32 | Blue Swirl | #define DPRINTF(fmt, ...) do {} while(0) |
25 | 001faf32 | Blue Swirl | #define BADF(fmt, ...) \
|
26 | 001faf32 | Blue Swirl | do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0) |
27 | 0ff596d0 | pbrook | #endif
|
28 | 0ff596d0 | pbrook | |
29 | 0ff596d0 | pbrook | enum {
|
30 | 0ff596d0 | pbrook | SMBUS_IDLE, |
31 | 0ff596d0 | pbrook | SMBUS_WRITE_DATA, |
32 | 0ff596d0 | pbrook | SMBUS_RECV_BYTE, |
33 | 0ff596d0 | pbrook | SMBUS_READ_DATA, |
34 | 0ff596d0 | pbrook | SMBUS_DONE, |
35 | 0ff596d0 | pbrook | SMBUS_CONFUSED = -1
|
36 | 0ff596d0 | pbrook | }; |
37 | 0ff596d0 | pbrook | |
38 | 0ff596d0 | pbrook | static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) |
39 | 0ff596d0 | pbrook | { |
40 | b5ea9327 | Anthony Liguori | SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); |
41 | 1ea96673 | Paul Brook | |
42 | 0ff596d0 | pbrook | DPRINTF("Quick Command %d\n", recv);
|
43 | b5ea9327 | Anthony Liguori | if (sc->quick_cmd) {
|
44 | b5ea9327 | Anthony Liguori | sc->quick_cmd(dev, recv); |
45 | b5ea9327 | Anthony Liguori | } |
46 | 0ff596d0 | pbrook | } |
47 | 0ff596d0 | pbrook | |
48 | 0ff596d0 | pbrook | static void smbus_do_write(SMBusDevice *dev) |
49 | 0ff596d0 | pbrook | { |
50 | b5ea9327 | Anthony Liguori | SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); |
51 | 1ea96673 | Paul Brook | |
52 | 0ff596d0 | pbrook | if (dev->data_len == 0) { |
53 | 0ff596d0 | pbrook | smbus_do_quick_cmd(dev, 0);
|
54 | 0ff596d0 | pbrook | } else if (dev->data_len == 1) { |
55 | 0ff596d0 | pbrook | DPRINTF("Send Byte\n");
|
56 | b5ea9327 | Anthony Liguori | if (sc->send_byte) {
|
57 | b5ea9327 | Anthony Liguori | sc->send_byte(dev, dev->data_buf[0]);
|
58 | 0ff596d0 | pbrook | } |
59 | 0ff596d0 | pbrook | } else {
|
60 | 0ff596d0 | pbrook | dev->command = dev->data_buf[0];
|
61 | 0ff596d0 | pbrook | DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1); |
62 | b5ea9327 | Anthony Liguori | if (sc->write_data) {
|
63 | b5ea9327 | Anthony Liguori | sc->write_data(dev, dev->command, dev->data_buf + 1,
|
64 | b5ea9327 | Anthony Liguori | dev->data_len - 1);
|
65 | 0ff596d0 | pbrook | } |
66 | 0ff596d0 | pbrook | } |
67 | 0ff596d0 | pbrook | } |
68 | 0ff596d0 | pbrook | |
69 | 9e07bdf8 | Anthony Liguori | static void smbus_i2c_event(I2CSlave *s, enum i2c_event event) |
70 | 0ff596d0 | pbrook | { |
71 | b5ea9327 | Anthony Liguori | SMBusDevice *dev = SMBUS_DEVICE(s); |
72 | 1ea96673 | Paul Brook | |
73 | 0ff596d0 | pbrook | switch (event) {
|
74 | 0ff596d0 | pbrook | case I2C_START_SEND:
|
75 | 0ff596d0 | pbrook | switch (dev->mode) {
|
76 | 0ff596d0 | pbrook | case SMBUS_IDLE:
|
77 | 0ff596d0 | pbrook | DPRINTF("Incoming data\n");
|
78 | 0ff596d0 | pbrook | dev->mode = SMBUS_WRITE_DATA; |
79 | 0ff596d0 | pbrook | break;
|
80 | 0ff596d0 | pbrook | default:
|
81 | 0ff596d0 | pbrook | BADF("Unexpected send start condition in state %d\n", dev->mode);
|
82 | 0ff596d0 | pbrook | dev->mode = SMBUS_CONFUSED; |
83 | 0ff596d0 | pbrook | break;
|
84 | 0ff596d0 | pbrook | } |
85 | 0ff596d0 | pbrook | break;
|
86 | 0ff596d0 | pbrook | |
87 | 0ff596d0 | pbrook | case I2C_START_RECV:
|
88 | 0ff596d0 | pbrook | switch (dev->mode) {
|
89 | 0ff596d0 | pbrook | case SMBUS_IDLE:
|
90 | 0ff596d0 | pbrook | DPRINTF("Read mode\n");
|
91 | 0ff596d0 | pbrook | dev->mode = SMBUS_RECV_BYTE; |
92 | 0ff596d0 | pbrook | break;
|
93 | 0ff596d0 | pbrook | case SMBUS_WRITE_DATA:
|
94 | 0ff596d0 | pbrook | if (dev->data_len == 0) { |
95 | 0ff596d0 | pbrook | BADF("Read after write with no data\n");
|
96 | 0ff596d0 | pbrook | dev->mode = SMBUS_CONFUSED; |
97 | 0ff596d0 | pbrook | } else {
|
98 | 0ff596d0 | pbrook | if (dev->data_len > 1) { |
99 | 0ff596d0 | pbrook | smbus_do_write(dev); |
100 | 0ff596d0 | pbrook | } else {
|
101 | 0ff596d0 | pbrook | dev->command = dev->data_buf[0];
|
102 | 0ff596d0 | pbrook | DPRINTF("%02x: Command %d\n", dev->i2c.address,
|
103 | 0ff596d0 | pbrook | dev->command); |
104 | 0ff596d0 | pbrook | } |
105 | 0ff596d0 | pbrook | DPRINTF("Read mode\n");
|
106 | 0ff596d0 | pbrook | dev->data_len = 0;
|
107 | 0ff596d0 | pbrook | dev->mode = SMBUS_READ_DATA; |
108 | 0ff596d0 | pbrook | } |
109 | 0ff596d0 | pbrook | break;
|
110 | 0ff596d0 | pbrook | default:
|
111 | 0ff596d0 | pbrook | BADF("Unexpected recv start condition in state %d\n", dev->mode);
|
112 | 0ff596d0 | pbrook | dev->mode = SMBUS_CONFUSED; |
113 | 0ff596d0 | pbrook | break;
|
114 | 0ff596d0 | pbrook | } |
115 | 0ff596d0 | pbrook | break;
|
116 | 0ff596d0 | pbrook | |
117 | 0ff596d0 | pbrook | case I2C_FINISH:
|
118 | 0ff596d0 | pbrook | switch (dev->mode) {
|
119 | 0ff596d0 | pbrook | case SMBUS_WRITE_DATA:
|
120 | 0ff596d0 | pbrook | smbus_do_write(dev); |
121 | 0ff596d0 | pbrook | break;
|
122 | 0ff596d0 | pbrook | case SMBUS_RECV_BYTE:
|
123 | 0ff596d0 | pbrook | smbus_do_quick_cmd(dev, 1);
|
124 | 0ff596d0 | pbrook | break;
|
125 | 0ff596d0 | pbrook | case SMBUS_READ_DATA:
|
126 | 0ff596d0 | pbrook | BADF("Unexpected stop during receive\n");
|
127 | 0ff596d0 | pbrook | break;
|
128 | 0ff596d0 | pbrook | default:
|
129 | 0ff596d0 | pbrook | /* Nothing to do. */
|
130 | 0ff596d0 | pbrook | break;
|
131 | 0ff596d0 | pbrook | } |
132 | 0ff596d0 | pbrook | dev->mode = SMBUS_IDLE; |
133 | 0ff596d0 | pbrook | dev->data_len = 0;
|
134 | 0ff596d0 | pbrook | break;
|
135 | 0ff596d0 | pbrook | |
136 | 0ff596d0 | pbrook | case I2C_NACK:
|
137 | 0ff596d0 | pbrook | switch (dev->mode) {
|
138 | 0ff596d0 | pbrook | case SMBUS_DONE:
|
139 | 0ff596d0 | pbrook | /* Nothing to do. */
|
140 | 0ff596d0 | pbrook | break;
|
141 | 0ff596d0 | pbrook | case SMBUS_READ_DATA:
|
142 | 0ff596d0 | pbrook | dev->mode = SMBUS_DONE; |
143 | 0ff596d0 | pbrook | break;
|
144 | 0ff596d0 | pbrook | default:
|
145 | 0ff596d0 | pbrook | BADF("Unexpected NACK in state %d\n", dev->mode);
|
146 | 0ff596d0 | pbrook | dev->mode = SMBUS_CONFUSED; |
147 | 0ff596d0 | pbrook | break;
|
148 | 0ff596d0 | pbrook | } |
149 | 0ff596d0 | pbrook | } |
150 | 0ff596d0 | pbrook | } |
151 | 0ff596d0 | pbrook | |
152 | 9e07bdf8 | Anthony Liguori | static int smbus_i2c_recv(I2CSlave *s) |
153 | 0ff596d0 | pbrook | { |
154 | b5ea9327 | Anthony Liguori | SMBusDevice *dev = SMBUS_DEVICE(s); |
155 | b5ea9327 | Anthony Liguori | SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); |
156 | 0ff596d0 | pbrook | int ret;
|
157 | 0ff596d0 | pbrook | |
158 | 0ff596d0 | pbrook | switch (dev->mode) {
|
159 | 0ff596d0 | pbrook | case SMBUS_RECV_BYTE:
|
160 | b5ea9327 | Anthony Liguori | if (sc->receive_byte) {
|
161 | b5ea9327 | Anthony Liguori | ret = sc->receive_byte(dev); |
162 | 0ff596d0 | pbrook | } else {
|
163 | 0ff596d0 | pbrook | ret = 0;
|
164 | 0ff596d0 | pbrook | } |
165 | 0ff596d0 | pbrook | DPRINTF("Receive Byte %02x\n", ret);
|
166 | 0ff596d0 | pbrook | dev->mode = SMBUS_DONE; |
167 | 0ff596d0 | pbrook | break;
|
168 | 0ff596d0 | pbrook | case SMBUS_READ_DATA:
|
169 | b5ea9327 | Anthony Liguori | if (sc->read_data) {
|
170 | b5ea9327 | Anthony Liguori | ret = sc->read_data(dev, dev->command, dev->data_len); |
171 | 0ff596d0 | pbrook | dev->data_len++; |
172 | 0ff596d0 | pbrook | } else {
|
173 | 0ff596d0 | pbrook | ret = 0;
|
174 | 0ff596d0 | pbrook | } |
175 | 0ff596d0 | pbrook | DPRINTF("Read data %02x\n", ret);
|
176 | 0ff596d0 | pbrook | break;
|
177 | 0ff596d0 | pbrook | default:
|
178 | 0ff596d0 | pbrook | BADF("Unexpected read in state %d\n", dev->mode);
|
179 | 0ff596d0 | pbrook | dev->mode = SMBUS_CONFUSED; |
180 | 0ff596d0 | pbrook | ret = 0;
|
181 | 0ff596d0 | pbrook | break;
|
182 | 0ff596d0 | pbrook | } |
183 | 0ff596d0 | pbrook | return ret;
|
184 | 0ff596d0 | pbrook | } |
185 | 0ff596d0 | pbrook | |
186 | 9e07bdf8 | Anthony Liguori | static int smbus_i2c_send(I2CSlave *s, uint8_t data) |
187 | 0ff596d0 | pbrook | { |
188 | b5ea9327 | Anthony Liguori | SMBusDevice *dev = SMBUS_DEVICE(s); |
189 | 1ea96673 | Paul Brook | |
190 | 0ff596d0 | pbrook | switch (dev->mode) {
|
191 | 0ff596d0 | pbrook | case SMBUS_WRITE_DATA:
|
192 | 0ff596d0 | pbrook | DPRINTF("Write data %02x\n", data);
|
193 | 0ff596d0 | pbrook | dev->data_buf[dev->data_len++] = data; |
194 | 0ff596d0 | pbrook | break;
|
195 | 0ff596d0 | pbrook | default:
|
196 | 0ff596d0 | pbrook | BADF("Unexpected write in state %d\n", dev->mode);
|
197 | 0ff596d0 | pbrook | break;
|
198 | 0ff596d0 | pbrook | } |
199 | 0ff596d0 | pbrook | return 0; |
200 | 0ff596d0 | pbrook | } |
201 | 0ff596d0 | pbrook | |
202 | 9e07bdf8 | Anthony Liguori | static int smbus_device_init(I2CSlave *i2c) |
203 | 0ff596d0 | pbrook | { |
204 | b5ea9327 | Anthony Liguori | SMBusDevice *dev = SMBUS_DEVICE(i2c); |
205 | b5ea9327 | Anthony Liguori | SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); |
206 | 0ff596d0 | pbrook | |
207 | b5ea9327 | Anthony Liguori | return sc->init(dev);
|
208 | 1ea96673 | Paul Brook | } |
209 | 0ff596d0 | pbrook | |
210 | 0ff596d0 | pbrook | /* Master device commands. */
|
211 | 5b7f5327 | Juan Quintela | void smbus_quick_command(i2c_bus *bus, uint8_t addr, int read) |
212 | 0ff596d0 | pbrook | { |
213 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, read); |
214 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
215 | 0ff596d0 | pbrook | } |
216 | 0ff596d0 | pbrook | |
217 | 5b7f5327 | Juan Quintela | uint8_t smbus_receive_byte(i2c_bus *bus, uint8_t addr) |
218 | 0ff596d0 | pbrook | { |
219 | 0ff596d0 | pbrook | uint8_t data; |
220 | 0ff596d0 | pbrook | |
221 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 1);
|
222 | 0ff596d0 | pbrook | data = i2c_recv(bus); |
223 | 0ff596d0 | pbrook | i2c_nack(bus); |
224 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
225 | 0ff596d0 | pbrook | return data;
|
226 | 0ff596d0 | pbrook | } |
227 | 0ff596d0 | pbrook | |
228 | 5b7f5327 | Juan Quintela | void smbus_send_byte(i2c_bus *bus, uint8_t addr, uint8_t data)
|
229 | 0ff596d0 | pbrook | { |
230 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 0);
|
231 | 0ff596d0 | pbrook | i2c_send(bus, data); |
232 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
233 | 0ff596d0 | pbrook | } |
234 | 0ff596d0 | pbrook | |
235 | 5b7f5327 | Juan Quintela | uint8_t smbus_read_byte(i2c_bus *bus, uint8_t addr, uint8_t command) |
236 | 0ff596d0 | pbrook | { |
237 | 0ff596d0 | pbrook | uint8_t data; |
238 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 0);
|
239 | 0ff596d0 | pbrook | i2c_send(bus, command); |
240 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 1);
|
241 | 0ff596d0 | pbrook | data = i2c_recv(bus); |
242 | 0ff596d0 | pbrook | i2c_nack(bus); |
243 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
244 | 0ff596d0 | pbrook | return data;
|
245 | 0ff596d0 | pbrook | } |
246 | 0ff596d0 | pbrook | |
247 | 5b7f5327 | Juan Quintela | void smbus_write_byte(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t data)
|
248 | 0ff596d0 | pbrook | { |
249 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 0);
|
250 | 0ff596d0 | pbrook | i2c_send(bus, command); |
251 | 0ff596d0 | pbrook | i2c_send(bus, data); |
252 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
253 | 0ff596d0 | pbrook | } |
254 | 0ff596d0 | pbrook | |
255 | 5b7f5327 | Juan Quintela | uint16_t smbus_read_word(i2c_bus *bus, uint8_t addr, uint8_t command) |
256 | 0ff596d0 | pbrook | { |
257 | 0ff596d0 | pbrook | uint16_t data; |
258 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 0);
|
259 | 0ff596d0 | pbrook | i2c_send(bus, command); |
260 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 1);
|
261 | 0ff596d0 | pbrook | data = i2c_recv(bus); |
262 | 0ff596d0 | pbrook | data |= i2c_recv(bus) << 8;
|
263 | 0ff596d0 | pbrook | i2c_nack(bus); |
264 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
265 | 0ff596d0 | pbrook | return data;
|
266 | 0ff596d0 | pbrook | } |
267 | 0ff596d0 | pbrook | |
268 | 5b7f5327 | Juan Quintela | void smbus_write_word(i2c_bus *bus, uint8_t addr, uint8_t command, uint16_t data)
|
269 | 0ff596d0 | pbrook | { |
270 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 0);
|
271 | 0ff596d0 | pbrook | i2c_send(bus, command); |
272 | 0ff596d0 | pbrook | i2c_send(bus, data & 0xff);
|
273 | 0ff596d0 | pbrook | i2c_send(bus, data >> 8);
|
274 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
275 | 0ff596d0 | pbrook | } |
276 | 0ff596d0 | pbrook | |
277 | 5b7f5327 | Juan Quintela | int smbus_read_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data)
|
278 | 0ff596d0 | pbrook | { |
279 | 0ff596d0 | pbrook | int len;
|
280 | 0ff596d0 | pbrook | int i;
|
281 | 0ff596d0 | pbrook | |
282 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 0);
|
283 | 0ff596d0 | pbrook | i2c_send(bus, command); |
284 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 1);
|
285 | 0ff596d0 | pbrook | len = i2c_recv(bus); |
286 | 0ff596d0 | pbrook | if (len > 32) |
287 | 0ff596d0 | pbrook | len = 0;
|
288 | 0ff596d0 | pbrook | for (i = 0; i < len; i++) |
289 | 0ff596d0 | pbrook | data[i] = i2c_recv(bus); |
290 | 0ff596d0 | pbrook | i2c_nack(bus); |
291 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
292 | 0ff596d0 | pbrook | return len;
|
293 | 0ff596d0 | pbrook | } |
294 | 0ff596d0 | pbrook | |
295 | 5b7f5327 | Juan Quintela | void smbus_write_block(i2c_bus *bus, uint8_t addr, uint8_t command, uint8_t *data,
|
296 | 0ff596d0 | pbrook | int len)
|
297 | 0ff596d0 | pbrook | { |
298 | 0ff596d0 | pbrook | int i;
|
299 | 0ff596d0 | pbrook | |
300 | 0ff596d0 | pbrook | if (len > 32) |
301 | 0ff596d0 | pbrook | len = 32;
|
302 | 0ff596d0 | pbrook | |
303 | 0ff596d0 | pbrook | i2c_start_transfer(bus, addr, 0);
|
304 | 0ff596d0 | pbrook | i2c_send(bus, command); |
305 | 0ff596d0 | pbrook | i2c_send(bus, len); |
306 | 0ff596d0 | pbrook | for (i = 0; i < len; i++) |
307 | 0ff596d0 | pbrook | i2c_send(bus, data[i]); |
308 | 0ff596d0 | pbrook | i2c_end_transfer(bus); |
309 | 0ff596d0 | pbrook | } |
310 | b5ea9327 | Anthony Liguori | |
311 | b5ea9327 | Anthony Liguori | static void smbus_device_class_init(ObjectClass *klass, void *data) |
312 | b5ea9327 | Anthony Liguori | { |
313 | b5ea9327 | Anthony Liguori | I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); |
314 | b5ea9327 | Anthony Liguori | |
315 | b5ea9327 | Anthony Liguori | sc->init = smbus_device_init; |
316 | b5ea9327 | Anthony Liguori | sc->event = smbus_i2c_event; |
317 | b5ea9327 | Anthony Liguori | sc->recv = smbus_i2c_recv; |
318 | b5ea9327 | Anthony Liguori | sc->send = smbus_i2c_send; |
319 | b5ea9327 | Anthony Liguori | } |
320 | b5ea9327 | Anthony Liguori | |
321 | b5ea9327 | Anthony Liguori | static TypeInfo smbus_device_type_info = {
|
322 | b5ea9327 | Anthony Liguori | .name = TYPE_SMBUS_DEVICE, |
323 | b5ea9327 | Anthony Liguori | .parent = TYPE_I2C_SLAVE, |
324 | b5ea9327 | Anthony Liguori | .instance_size = sizeof(SMBusDevice),
|
325 | b5ea9327 | Anthony Liguori | .abstract = true,
|
326 | b5ea9327 | Anthony Liguori | .class_size = sizeof(SMBusDeviceClass),
|
327 | b5ea9327 | Anthony Liguori | .class_init = smbus_device_class_init, |
328 | b5ea9327 | Anthony Liguori | }; |
329 | b5ea9327 | Anthony Liguori | |
330 | 83f7d43a | Andreas Färber | static void smbus_device_register_types(void) |
331 | b5ea9327 | Anthony Liguori | { |
332 | b5ea9327 | Anthony Liguori | type_register_static(&smbus_device_type_info); |
333 | b5ea9327 | Anthony Liguori | } |
334 | b5ea9327 | Anthony Liguori | |
335 | 83f7d43a | Andreas Färber | type_init(smbus_device_register_types) |