This source file includes following definitions.
- amdiic_match
- amdiic_attach
- amdiic_read
- amdiic_write
- amdiic_wait
- amdiic_i2c_acquire_bus
- amdiic_i2c_release_bus
- amdiic_i2c_exec
- amdiic_intr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 #include <sys/param.h>
24 #include <sys/systm.h>
25 #include <sys/device.h>
26 #include <sys/kernel.h>
27 #include <sys/rwlock.h>
28 #include <sys/proc.h>
29
30 #include <machine/bus.h>
31
32 #include <dev/pci/pcidevs.h>
33 #include <dev/pci/pcireg.h>
34 #include <dev/pci/pcivar.h>
35
36 #include <dev/i2c/i2cvar.h>
37
38 #ifdef AMDIIC_DEBUG
39 #define DPRINTF(x) printf x
40 #else
41 #define DPRINTF(x)
42 #endif
43
44 #define AMDIIC_DELAY 100
45 #define AMDIIC_TIMEOUT 1
46
47
48 #define AMD8111_SMB_BASE 0x10
49 #define AMD8111_SMB_MISC 0x48
50 #define AMD8111_SMB_MISC_SU (1 << 0)
51 #define AMD8111_SMB_MISC_INTEN (1 << 1)
52 #define AMD8111_SMB_MISC_SCIEN (1 << 2)
53
54
55 #define AMD8111_SMB_SC_DATA 0x00
56 #define AMD8111_SMB_SC_ST 0x04
57 #define AMD8111_SMB_SC_ST_OBF (1 << 0)
58 #define AMD8111_SMB_SC_ST_IBF (1 << 1)
59 #define AMD8111_SMB_SC_ST_CMD (1 << 3)
60 #define AMD8111_SMB_SC_ST_BITS "\020\001OBF\002IBF\004CMD"
61 #define AMD8111_SMB_SC_CMD 0x04
62 #define AMD8111_SMB_SC_CMD_RD 0x80
63 #define AMD8111_SMB_SC_CMD_WR 0x81
64 #define AMD8111_SMB_SC_IC 0x08
65
66
67 #define AMD8111_SMB_PROTO 0x00
68 #define AMD8111_SMB_PROTO_READ 0x01
69 #define AMD8111_SMB_PROTO_QUICK 0x02
70 #define AMD8111_SMB_PROTO_BYTE 0x04
71 #define AMD8111_SMB_PROTO_BDATA 0x06
72 #define AMD8111_SMB_PROTO_WDATA 0x08
73 #define AMD8111_SMB_STAT 0x01
74 #define AMD8111_SMB_STAT_MASK 0x1f
75 #define AMD8111_SMB_STAT_DONE (1 << 7)
76 #define AMD8111_SMB_ADDR 0x02
77 #define AMD8111_SMB_ADDR_SHIFT 1
78 #define AMD8111_SMB_CMD 0x03
79 #define AMD8111_SMB_DATA(x) (0x04 + (x))
80
81 struct amdiic_softc {
82 struct device sc_dev;
83
84 bus_space_tag_t sc_iot;
85 bus_space_handle_t sc_ioh;
86 void * sc_ih;
87 int sc_poll;
88
89 struct i2c_controller sc_i2c_tag;
90 struct rwlock sc_i2c_lock;
91 struct {
92 i2c_op_t op;
93 void * buf;
94 size_t len;
95 int flags;
96 volatile int error;
97 } sc_i2c_xfer;
98 };
99
100 int amdiic_match(struct device *, void *, void *);
101 void amdiic_attach(struct device *, struct device *, void *);
102
103 int amdiic_read(struct amdiic_softc *, u_int8_t);
104 int amdiic_write(struct amdiic_softc *, u_int8_t, u_int8_t);
105 int amdiic_wait(struct amdiic_softc *, int);
106
107 int amdiic_i2c_acquire_bus(void *, int);
108 void amdiic_i2c_release_bus(void *, int);
109 int amdiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
110 void *, size_t, int);
111
112 int amdiic_intr(void *);
113
114 struct cfattach amdiic_ca = {
115 sizeof(struct amdiic_softc),
116 amdiic_match,
117 amdiic_attach
118 };
119
120 struct cfdriver amdiic_cd = {
121 NULL, "amdiic", DV_DULL
122 };
123
124 const struct pci_matchid amdiic_ids[] = {
125 { PCI_VENDOR_AMD, PCI_PRODUCT_AMD_8111_SMB }
126 };
127
128 int
129 amdiic_match(struct device *parent, void *match, void *aux)
130 {
131 return (pci_matchbyid(aux, amdiic_ids,
132 sizeof(amdiic_ids) / sizeof(amdiic_ids[0])));
133 }
134
135 void
136 amdiic_attach(struct device *parent, struct device *self, void *aux)
137 {
138 struct amdiic_softc *sc = (struct amdiic_softc *)self;
139 struct pci_attach_args *pa = aux;
140 struct i2cbus_attach_args iba;
141 pcireg_t conf;
142 bus_size_t iosize;
143 pci_intr_handle_t ih;
144 const char *intrstr = NULL;
145
146
147 if (pci_mapreg_map(pa, AMD8111_SMB_BASE, PCI_MAPREG_TYPE_IO, 0,
148 &sc->sc_iot, &sc->sc_ioh, NULL, &iosize, 0)) {
149 printf(": can't map I/O space\n");
150 return;
151 }
152
153
154 conf = pci_conf_read(pa->pa_pc, pa->pa_tag, AMD8111_SMB_MISC);
155 DPRINTF((": conf 0x%08x", conf));
156
157 sc->sc_poll = 1;
158 if (conf & AMD8111_SMB_MISC_SCIEN) {
159
160 printf(": SCI");
161 } else if (conf & AMD8111_SMB_MISC_INTEN) {
162
163 if (pci_intr_map(pa, &ih) == 0) {
164 intrstr = pci_intr_string(pa->pa_pc, ih);
165 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
166 amdiic_intr, sc, sc->sc_dev.dv_xname);
167 if (sc->sc_ih != NULL) {
168 printf(": %s", intrstr);
169 sc->sc_poll = 0;
170 }
171 }
172 if (sc->sc_poll)
173 printf(": polling");
174 }
175
176 printf("\n");
177
178
179 rw_init(&sc->sc_i2c_lock, "iiclk");
180 sc->sc_i2c_tag.ic_cookie = sc;
181 sc->sc_i2c_tag.ic_acquire_bus = amdiic_i2c_acquire_bus;
182 sc->sc_i2c_tag.ic_release_bus = amdiic_i2c_release_bus;
183 sc->sc_i2c_tag.ic_exec = amdiic_i2c_exec;
184
185 bzero(&iba, sizeof(iba));
186 iba.iba_name = "iic";
187 iba.iba_tag = &sc->sc_i2c_tag;
188 config_found(self, &iba, iicbus_print);
189
190 return;
191 }
192
193 int
194 amdiic_read(struct amdiic_softc *sc, u_int8_t reg)
195 {
196 if (amdiic_wait(sc, 0))
197 return (-1);
198 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMD8111_SMB_SC_CMD,
199 AMD8111_SMB_SC_CMD_RD);
200 if (amdiic_wait(sc, 0))
201 return (-1);
202 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMD8111_SMB_SC_DATA, reg);
203 if (amdiic_wait(sc, 1))
204 return (-1);
205
206 return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, AMD8111_SMB_SC_DATA));
207 }
208
209 int
210 amdiic_write(struct amdiic_softc *sc, u_int8_t reg, u_int8_t val)
211 {
212 if (amdiic_wait(sc, 0))
213 return (-1);
214 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMD8111_SMB_SC_CMD,
215 AMD8111_SMB_SC_CMD_WR);
216 if (amdiic_wait(sc, 0))
217 return (-1);
218 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMD8111_SMB_SC_DATA, reg);
219 if (amdiic_wait(sc, 0))
220 return (-1);
221 bus_space_write_1(sc->sc_iot, sc->sc_ioh, AMD8111_SMB_SC_DATA, val);
222
223 return (0);
224 }
225
226 int
227 amdiic_wait(struct amdiic_softc *sc, int output)
228 {
229 int retries;
230 u_int8_t st;
231
232 for (retries = 100; retries > 0; retries--) {
233 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
234 AMD8111_SMB_SC_ST);
235 if (output && (st & AMD8111_SMB_SC_ST_OBF))
236 return (0);
237 if (!output && (st & AMD8111_SMB_SC_ST_IBF) == 0)
238 return (0);
239 DELAY(1);
240 }
241 DPRINTF(("%s: %s wait timeout: st 0x%b\n", sc->sc_dev.dv_xname,
242 (output ? "output" : "input"), st));
243
244 return (1);
245 }
246
247 int
248 amdiic_i2c_acquire_bus(void *cookie, int flags)
249 {
250 struct amdiic_softc *sc = cookie;
251
252 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
253 return (0);
254
255 return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
256 }
257
258 void
259 amdiic_i2c_release_bus(void *cookie, int flags)
260 {
261 struct amdiic_softc *sc = cookie;
262
263 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
264 return;
265
266 rw_exit(&sc->sc_i2c_lock);
267 }
268
269 int
270 amdiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
271 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
272 {
273 struct amdiic_softc *sc = cookie;
274 u_int8_t *b;
275 u_int8_t proto, st;
276 int retries;
277
278 DPRINTF(("%s: exec: op %d, addr 0x%02x, cmdlen %d, len %d, "
279 "flags 0x%02x\n", sc->sc_dev.dv_xname, op, addr,
280 cmdlen, len, flags));
281
282 if (cold || sc->sc_poll)
283 flags |= I2C_F_POLL;
284
285 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
286 return (1);
287
288
289 sc->sc_i2c_xfer.op = op;
290 sc->sc_i2c_xfer.buf = buf;
291 sc->sc_i2c_xfer.len = len;
292 sc->sc_i2c_xfer.flags = flags;
293 sc->sc_i2c_xfer.error = 0;
294
295
296 if (amdiic_write(sc, AMD8111_SMB_ADDR,
297 addr << AMD8111_SMB_ADDR_SHIFT) == -1)
298 return (1);
299
300 b = (void *)cmdbuf;
301 if (cmdlen > 0)
302
303 if (amdiic_write(sc, AMD8111_SMB_CMD, b[0]) == -1)
304 return (1);
305
306 if (I2C_OP_WRITE_P(op)) {
307
308 b = buf;
309 if (len > 0)
310 if (amdiic_write(sc, AMD8111_SMB_DATA(0), b[0]) == -1)
311 return (1);
312 if (len > 1)
313 if (amdiic_write(sc, AMD8111_SMB_DATA(1), b[1]) == -1)
314 return (1);
315 }
316
317
318 if (len == 0)
319 proto = AMD8111_SMB_PROTO_BYTE;
320 else if (len == 1)
321 proto = AMD8111_SMB_PROTO_BDATA;
322 else if (len == 2)
323 proto = AMD8111_SMB_PROTO_WDATA;
324
325
326 if (I2C_OP_READ_P(op))
327 proto |= AMD8111_SMB_PROTO_READ;
328
329
330 amdiic_write(sc, AMD8111_SMB_PROTO, proto);
331
332 if (flags & I2C_F_POLL) {
333
334 DELAY(AMDIIC_DELAY);
335 for (retries = 1000; retries > 0; retries--) {
336 st = amdiic_read(sc, AMD8111_SMB_STAT);
337 if (st != 0)
338 break;
339 DELAY(AMDIIC_DELAY);
340 }
341 if (st == 0) {
342 printf("%s: exec: op %d, addr 0x%02x, cmdlen %d, "
343 "len %d, flags 0x%02x: timeout\n",
344 sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags);
345 return (1);
346 }
347 amdiic_intr(sc);
348 } else {
349
350 if (tsleep(sc, PRIBIO, "iicexec", AMDIIC_TIMEOUT * hz))
351 return (1);
352 }
353
354 if (sc->sc_i2c_xfer.error)
355 return (1);
356
357 return (0);
358 }
359
360 int
361 amdiic_intr(void *arg)
362 {
363 struct amdiic_softc *sc = arg;
364 int st;
365 u_int8_t *b;
366 size_t len;
367
368
369 if ((st = amdiic_read(sc, AMD8111_SMB_STAT)) == -1)
370 return (-1);
371 if (st == 0)
372
373 return (0);
374
375 DPRINTF(("%s: intr: st 0x%02x\n", sc->sc_dev.dv_xname, st));
376
377
378 if ((st & AMD8111_SMB_STAT_MASK) != 0) {
379 sc->sc_i2c_xfer.error = 1;
380 goto done;
381 }
382
383 if (st & AMD8111_SMB_STAT_DONE) {
384 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
385 goto done;
386
387
388 b = sc->sc_i2c_xfer.buf;
389 len = sc->sc_i2c_xfer.len;
390 if (len > 0)
391 b[0] = amdiic_read(sc, AMD8111_SMB_DATA(0));
392 if (len > 1)
393 b[1] = amdiic_read(sc, AMD8111_SMB_DATA(1));
394 }
395
396 done:
397 if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
398 wakeup(sc);
399 return (1);
400 }