This source file includes following definitions.
- viapm_match
- viapm_attach
- viapm_i2c_acquire_bus
- viapm_i2c_release_bus
- viapm_i2c_exec
- viapm_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
39
40
41
42
43 #define VIAPM_SMB_BASE 0xd0
44 #define VIAPM_SMB_HOSTC 0xd2
45 #define VIAPM_SMB_HOSTC_HSTEN (1 << 0)
46 #define VIAPM_SMB_HOSTC_INTEN (1 << 1)
47 #define VIAPM_SMB_HOSTC_SCIEN (1 << 3)
48
49
50 #define VIAPM_SMB_HS 0x00
51 #define VIAPM_SMB_HS_BUSY (1 << 0)
52 #define VIAPM_SMB_HS_INTR (1 << 1)
53 #define VIAPM_SMB_HS_DEVERR (1 << 2)
54 #define VIAPM_SMB_HS_BUSERR (1 << 3)
55 #define VIAPM_SMB_HS_FAILED (1 << 4)
56 #define VIAPM_SMB_HS_INUSE (1 << 6)
57 #define VIAPM_SMB_HS_BITS \
58 "\020\001BUSY\002INTR\003DEVERR\004BUSERR\005FAILED\007INUSE"
59 #define VIAPM_SMB_HC 0x02
60 #define VIAPM_SMB_HC_INTREN (1 << 0)
61 #define VIAPM_SMB_HC_KILL (1 << 1)
62 #define VIAPM_SMB_HC_CMD_QUICK (0 << 2)
63 #define VIAPM_SMB_HC_CMD_BYTE (1 << 2)
64 #define VIAPM_SMB_HC_CMD_BDATA (2 << 2)
65 #define VIAPM_SMB_HC_CMD_WDATA (3 << 2)
66 #define VIAPM_SMB_HC_CMD_PCALL (4 << 2)
67 #define VIAPM_SMB_HC_CMD_BLOCK (5 << 2)
68 #define VIAPM_SMB_HC_START (1 << 6)
69 #define VIAPM_SMB_HCMD 0x03
70 #define VIAPM_SMB_TXSLVA 0x04
71 #define VIAPM_SMB_TXSLVA_READ (1 << 0)
72 #define VIAPM_SMB_TXSLVA_ADDR(x) (((x) & 0x7f) << 1)
73 #define VIAPM_SMB_HD0 0x05
74 #define VIAPM_SMB_HD1 0x06
75 #define VIAPM_SMB_HBDB 0x07
76
77 #define VIAPM_SMB_SIZE 16
78
79 #ifdef VIAPM_DEBUG
80 #define DPRINTF(x) printf x
81 #else
82 #define DPRINTF(x)
83 #endif
84
85 #define VIAPM_DELAY 100
86 #define VIAPM_TIMEOUT 1
87
88 struct viapm_softc {
89 struct device sc_dev;
90
91 bus_space_tag_t sc_iot;
92 bus_space_handle_t sc_ioh;
93 void * sc_ih;
94 int sc_poll;
95
96 struct i2c_controller sc_i2c_tag;
97 struct rwlock sc_i2c_lock;
98 struct {
99 i2c_op_t op;
100 void * buf;
101 size_t len;
102 int flags;
103 volatile int error;
104 } sc_i2c_xfer;
105 };
106
107 int viapm_match(struct device *, void *, void *);
108 void viapm_attach(struct device *, struct device *, void *);
109
110 int viapm_i2c_acquire_bus(void *, int);
111 void viapm_i2c_release_bus(void *, int);
112 int viapm_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
113 void *, size_t, int);
114
115 int viapm_intr(void *);
116
117 struct cfattach viapm_ca = {
118 sizeof(struct viapm_softc),
119 viapm_match,
120 viapm_attach
121 };
122
123 struct cfdriver viapm_cd = {
124 NULL, "viapm", DV_DULL
125 };
126
127 const struct pci_matchid viapm_ids[] = {
128 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233_ISA },
129 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8233A_ISA },
130 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8235_ISA },
131 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237_ISA },
132 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8237A_ISA },
133 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_VT8251_ISA },
134 { PCI_VENDOR_VIATECH, PCI_PRODUCT_VIATECH_CX700_ISA }
135 };
136
137 int
138 viapm_match(struct device *parent, void *match, void *aux)
139 {
140 return (pci_matchbyid(aux, viapm_ids,
141 sizeof(viapm_ids) / sizeof(viapm_ids[0])));
142 }
143
144 void
145 viapm_attach(struct device *parent, struct device *self, void *aux)
146 {
147 struct viapm_softc *sc = (struct viapm_softc *)self;
148 struct pci_attach_args *pa = aux;
149 struct i2cbus_attach_args iba;
150 pcireg_t conf, iobase;
151 #if 0
152 pci_intr_handle_t ih;
153 const char *intrstr = NULL;
154 #endif
155
156
157 sc->sc_iot = pa->pa_iot;
158 iobase = pci_conf_read(pa->pa_pc, pa->pa_tag, VIAPM_SMB_BASE);
159 if (iobase == 0 ||
160 bus_space_map(sc->sc_iot, iobase & 0xfffe,
161 VIAPM_SMB_SIZE, 0, &sc->sc_ioh)) {
162 printf(": can't map I/O space\n");
163 return;
164 }
165
166
167 conf = (iobase >> 16);
168 DPRINTF((": conf 0x%x", conf));
169
170 if ((conf & VIAPM_SMB_HOSTC_HSTEN) == 0) {
171 printf(": SMBus host disabled\n");
172 goto fail;
173 }
174
175 if (conf & VIAPM_SMB_HOSTC_INTEN) {
176 if (conf & VIAPM_SMB_HOSTC_SCIEN)
177 printf(": SCI");
178 else
179 printf(": SMI");
180 sc->sc_poll = 1;
181 } else {
182 #if 0
183
184 if (pci_intr_map(pa, &ih)) {
185 printf(": can't map interrupt\n");
186 goto fail;
187 }
188 intrstr = pci_intr_string(pa->pa_pc, ih);
189 sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO,
190 viapm_intr, sc, sc->sc_dev.dv_xname);
191 if (sc->sc_ih == NULL) {
192 printf(": can't establish interrupt");
193 if (intrstr != NULL)
194 printf(" at %s", intrstr);
195 printf("\n");
196 goto fail;
197 }
198 printf(": %s", intrstr);
199 #endif
200 sc->sc_poll = 1;
201 }
202
203 printf("\n");
204
205
206 rw_init(&sc->sc_i2c_lock, "iiclk");
207 sc->sc_i2c_tag.ic_cookie = sc;
208 sc->sc_i2c_tag.ic_acquire_bus = viapm_i2c_acquire_bus;
209 sc->sc_i2c_tag.ic_release_bus = viapm_i2c_release_bus;
210 sc->sc_i2c_tag.ic_exec = viapm_i2c_exec;
211
212 bzero(&iba, sizeof iba);
213 iba.iba_name = "iic";
214 iba.iba_tag = &sc->sc_i2c_tag;
215 config_found(self, &iba, iicbus_print);
216
217 return;
218
219 fail:
220 bus_space_unmap(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_SIZE);
221 }
222
223 int
224 viapm_i2c_acquire_bus(void *cookie, int flags)
225 {
226 struct viapm_softc *sc = cookie;
227
228 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
229 return (0);
230
231 return (rw_enter(&sc->sc_i2c_lock, RW_WRITE | RW_INTR));
232 }
233
234 void
235 viapm_i2c_release_bus(void *cookie, int flags)
236 {
237 struct viapm_softc *sc = cookie;
238
239 if (cold || sc->sc_poll || (flags & I2C_F_POLL))
240 return;
241
242 rw_exit(&sc->sc_i2c_lock);
243 }
244
245 int
246 viapm_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
247 const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
248 {
249 struct viapm_softc *sc = cookie;
250 u_int8_t *b;
251 u_int8_t ctl, st;
252 int retries;
253
254 DPRINTF(("%s: exec op %d, addr 0x%x, cmdlen %d, len %d, "
255 "flags 0x%x, status 0x%b\n", sc->sc_dev.dv_xname, op, addr,
256 cmdlen, len, flags, bus_space_read_1(sc->sc_iot, sc->sc_ioh,
257 VIAPM_SMB_HS), VIAPM_SMB_HS_BITS));
258
259
260 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS);
261 DPRINTF(("%s: exec: st 0x%b\n", sc->sc_dev.dv_xname, st,
262 VIAPM_SMB_HS_BITS));
263 if (st & VIAPM_SMB_HS_BUSY)
264 return (1);
265
266 if (cold || sc->sc_poll)
267 flags |= I2C_F_POLL;
268
269 if (!I2C_OP_STOP_P(op) || cmdlen > 1 || len > 2)
270 return (1);
271
272
273 sc->sc_i2c_xfer.op = op;
274 sc->sc_i2c_xfer.buf = buf;
275 sc->sc_i2c_xfer.len = len;
276 sc->sc_i2c_xfer.flags = flags;
277 sc->sc_i2c_xfer.error = 0;
278
279
280 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_TXSLVA,
281 VIAPM_SMB_TXSLVA_ADDR(addr) |
282 (I2C_OP_READ_P(op) ? VIAPM_SMB_TXSLVA_READ : 0));
283
284 b = (void *)cmdbuf;
285 if (cmdlen > 0)
286
287 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
288 VIAPM_SMB_HCMD, b[0]);
289
290 if (I2C_OP_WRITE_P(op)) {
291
292 b = buf;
293 if (len > 0)
294 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
295 VIAPM_SMB_HD0, b[0]);
296 if (len > 1)
297 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
298 VIAPM_SMB_HD1, b[1]);
299 }
300
301
302 if (len == 0)
303 ctl = VIAPM_SMB_HC_CMD_BYTE;
304 else if (len == 1)
305 ctl = VIAPM_SMB_HC_CMD_BDATA;
306 else if (len == 2)
307 ctl = VIAPM_SMB_HC_CMD_WDATA;
308
309 if ((flags & I2C_F_POLL) == 0)
310 ctl |= VIAPM_SMB_HC_INTREN;
311
312
313 ctl |= VIAPM_SMB_HC_START;
314 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HC, ctl);
315
316 if (flags & I2C_F_POLL) {
317
318 DELAY(VIAPM_DELAY);
319 for (retries = 1000; retries > 0; retries--) {
320 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
321 VIAPM_SMB_HS);
322 if ((st & VIAPM_SMB_HS_BUSY) == 0)
323 break;
324 DELAY(VIAPM_DELAY);
325 }
326 if (st & VIAPM_SMB_HS_BUSY)
327 goto timeout;
328 viapm_intr(sc);
329 } else {
330
331 if (tsleep(sc, PRIBIO, "iicexec", VIAPM_TIMEOUT * hz))
332 goto timeout;
333 }
334
335 if (sc->sc_i2c_xfer.error)
336 return (1);
337
338 return (0);
339
340 timeout:
341
342
343
344 printf("%s: timeout, status 0x%b\n", sc->sc_dev.dv_xname, st,
345 VIAPM_SMB_HS_BITS);
346 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HC,
347 VIAPM_SMB_HC_KILL);
348 DELAY(VIAPM_DELAY);
349 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS);
350 if ((st & VIAPM_SMB_HS_FAILED) == 0)
351 printf("%s: transaction abort failed, status 0x%b\n",
352 sc->sc_dev.dv_xname, st, VIAPM_SMB_HS_BITS);
353 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS, st);
354 return (1);
355 }
356
357 int
358 viapm_intr(void *arg)
359 {
360 struct viapm_softc *sc = arg;
361 u_int8_t st;
362 u_int8_t *b;
363 size_t len;
364
365
366 st = bus_space_read_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS);
367 if ((st & VIAPM_SMB_HS_BUSY) != 0 || (st & (VIAPM_SMB_HS_INTR |
368 VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
369 VIAPM_SMB_HS_FAILED)) == 0)
370
371 return (0);
372
373 DPRINTF(("%s: intr st 0x%b\n", sc->sc_dev.dv_xname, st,
374 VIAPM_SMB_HS_BITS));
375
376
377 bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIAPM_SMB_HS, st);
378
379
380 if (st & (VIAPM_SMB_HS_DEVERR | VIAPM_SMB_HS_BUSERR |
381 VIAPM_SMB_HS_FAILED)) {
382 sc->sc_i2c_xfer.error = 1;
383 goto done;
384 }
385
386 if (st & VIAPM_SMB_HS_INTR) {
387 if (I2C_OP_WRITE_P(sc->sc_i2c_xfer.op))
388 goto done;
389
390
391 b = sc->sc_i2c_xfer.buf;
392 len = sc->sc_i2c_xfer.len;
393 if (len > 0)
394 b[0] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
395 VIAPM_SMB_HD0);
396 if (len > 1)
397 b[1] = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
398 VIAPM_SMB_HD1);
399 }
400
401 done:
402 if ((sc->sc_i2c_xfer.flags & I2C_F_POLL) == 0)
403 wakeup(sc);
404 return (1);
405 }