ig4 - Use interrupt to wait for receive data
[dragonfly.git] / sys / bus / smbus / ichiic / ig4_iic.c
1 /*
2  * Copyright (c) 2014 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * Intel 4th generation mobile cpus integrated I2C device, smbus driver.
36  *
37  * See ig4_reg.h for datasheet reference and notes.
38  */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <sys/errno.h>
45 #include <sys/lock.h>
46 #include <sys/mutex.h>
47 #include <sys/syslog.h>
48 #include <sys/bus.h>
49
50 #include <sys/rman.h>
51
52 #include <bus/pci/pcivar.h>
53 #include <bus/pci/pcireg.h>
54 #include <bus/smbus/smbconf.h>
55
56 #include "smbus_if.h"
57
58 #include "ig4_reg.h"
59 #include "ig4_var.h"
60
61 #define TRANS_NORMAL    1
62 #define TRANS_PCALL     2
63 #define TRANS_BLOCK     3
64
65 static void ig4iic_intr(void *cookie);
66
67 /*
68  * Low-level inline support functions
69  */
70 static __inline
71 void
72 reg_write(ig4iic_softc_t *sc, uint32_t reg, uint32_t value)
73 {
74         bus_space_write_4(sc->regs_t, sc->regs_h, reg, value);
75         bus_space_barrier(sc->regs_t, sc->regs_h, reg, 4,
76                           BUS_SPACE_BARRIER_WRITE);
77 }
78
79 static __inline
80 uint32_t
81 reg_read(ig4iic_softc_t *sc, uint32_t reg)
82 {
83         uint32_t value;
84
85         bus_space_barrier(sc->regs_t, sc->regs_h, reg, 4,
86                           BUS_SPACE_BARRIER_READ);
87         value = bus_space_read_4(sc->regs_t, sc->regs_h, reg);
88         return value;
89 }
90
91 /*
92  * Enable or disable the controller and wait for the controller to acknowledge
93  * the state change.
94  */
95 static
96 int
97 set_controller(ig4iic_softc_t *sc, uint32_t ctl)
98 {
99         int retry;
100         int error;
101         uint32_t v;
102
103         reg_write(sc, IG4_REG_I2C_EN, ctl);
104         error = SMB_ETIMEOUT;
105
106         for (retry = 100; retry > 0; --retry) {
107                 v = reg_read(sc, IG4_REG_ENABLE_STATUS);
108                 if (((v ^ ctl) & IG4_I2C_ENABLE) == 0) {
109                         error = 0;
110                         break;
111                 }
112                 tsleep(sc, 0, "i2cslv", 1);
113         }
114         return error;
115 }
116
117 /*
118  * Wait up to 25ms for the requested status using a 25uS polling loop.
119  */
120 static
121 int
122 wait_status(ig4iic_softc_t *sc, uint32_t status)
123 {
124         uint32_t v;
125         int error;
126         int txlvl = -1;
127         sysclock_t count;
128         sysclock_t limit;
129
130         error = SMB_ETIMEOUT;
131         count = sys_cputimer->count();
132         limit = sys_cputimer->freq / 40;
133
134         while (sys_cputimer->count() - count <= limit) {
135                 v = reg_read(sc, IG4_REG_I2C_STA);
136                 if (v & status) {
137                         error = 0;
138                         break;
139                 }
140
141                 if (status & IG4_STATUS_TX_EMPTY) {
142                         v = reg_read(sc, IG4_REG_TXFLR) & IG4_FIFOLVL_MASK;
143                         if (txlvl != v) {
144                                 txlvl = v;
145                                 count = sys_cputimer->count();
146                         }
147                 }
148
149                 if (status & IG4_STATUS_RX_NOTEMPTY) {
150                         lksleep(sc, &sc->lk, 0, "i2cwait", (hz + 99) / 100);
151                 } else {
152                         DELAY(25);
153                 }
154         }
155         return error;
156 }
157
158 /*
159  * Set the slave address.  The controller must be disabled when
160  * changing the address.
161  *
162  * This operation does not issue anything to the I2C bus but sets
163  * the target address for when the controller later issues a START.
164  */
165 static
166 void
167 set_slave_addr(ig4iic_softc_t *sc, uint8_t slave, int trans_op)
168 {
169         uint32_t tar;
170         uint32_t ctl;
171         int use_10bit;
172
173         use_10bit = sc->use_10bit;
174         if (trans_op & SMB_TRANS_7BIT)
175                 use_10bit = 0;
176         if (trans_op & SMB_TRANS_10BIT)
177                 use_10bit = 1;
178
179         if (sc->slave_valid && sc->last_slave == slave &&
180             sc->use_10bit == use_10bit) {
181                 return;
182         }
183         sc->use_10bit = use_10bit;
184
185         /*
186          * Wait for TXFIFO to drain before disabling the controller.
187          *
188          * If a write message has not been completed it's really a
189          * programming error, but for now in that case issue an extra
190          * byte + STOP.
191          *
192          * If a read message has not been completed it's also a programming
193          * error, for now just ignore it.
194          */
195         wait_status(sc, IG4_STATUS_TX_NOTFULL);
196         if (sc->write_started) {
197                 reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_STOP);
198                 sc->write_started = 0;
199         }
200         if (sc->read_started)
201                 sc->read_started = 0;
202         wait_status(sc, IG4_STATUS_TX_EMPTY);
203
204         set_controller(sc, 0);
205         ctl = reg_read(sc, IG4_REG_CTL);
206         ctl &= ~IG4_CTL_10BIT;
207         ctl |= IG4_CTL_RESTARTEN;
208
209         tar = slave;
210         if (sc->use_10bit) {
211                 tar |= IG4_TAR_10BIT;
212                 ctl |= IG4_CTL_10BIT;
213         }
214         reg_write(sc, IG4_REG_CTL, ctl);
215         reg_write(sc, IG4_REG_TAR_ADD, tar);
216         set_controller(sc, IG4_I2C_ENABLE);
217         sc->slave_valid = 1;
218         sc->last_slave = slave;
219 }
220
221 /*
222  * Issue START with byte command, possible count, and a variable length
223  * read or write buffer, then possible turn-around read.  The read also
224  * has a possible count received.
225  *
226  * For SMBUS -
227  *
228  * Quick:               START+ADDR+RD/WR STOP
229  *
230  * Normal:              START+ADDR+WR COMM DATA..DATA STOP
231  *
232  *                      START+ADDR+RD COMM
233  *                      RESTART+ADDR RDATA..RDATA STOP
234  *                      (can also be used for I2C transactions)
235  *
236  * Process Call:        START+ADDR+WR COMM DATAL DATAH
237  *                      RESTART+ADDR+RD RDATAL RDATAH STOP
238  *
239  * Block:               START+ADDR+RD COMM
240  *                      RESTART+ADDR+RD RCOUNT DATA... STOP
241  *
242  *                      START+ADDR+WR COMM
243  *                      RESTART+ADDR+WR WCOUNT DATA... STOP
244  *
245  * For I2C - basically, no *COUNT fields.
246  *
247  * Generally speaking, the START+ADDR / RESTART+ADDR is handled automatically
248  * by the controller at the beginning of a command sequence or on a data
249  * direction turn-around, and we only need to tell it when to issue the STOP.
250  */
251 static int
252 smb_transaction(ig4iic_softc_t *sc, char cmd, int op,
253                 char *wbuf, int wcount, char *rbuf, int rcount, int *actualp)
254 {
255         int error;
256         uint32_t last;
257
258         /*
259          * Issue START or RESTART with next data byte, clear any previous
260          * abort condition that may have been holding the txfifo in reset.
261          */
262         last = IG4_DATA_RESTART;
263         reg_read(sc, IG4_REG_CLR_TX_ABORT);
264         if (actualp)
265                 *actualp = 0;
266
267         /*
268          * Issue command if not told otherwise (smbus).
269          */
270         if ((op & SMB_TRANS_NOCMD) == 0) {
271                 error = wait_status(sc, IG4_STATUS_TX_NOTFULL);
272                 if (error)
273                         goto done;
274                 last |= (u_char)cmd;
275                 if (wcount == 0 && rcount == 0 && (op & SMB_TRANS_NOSTOP) == 0)
276                         last |= IG4_DATA_STOP;
277                 reg_write(sc, IG4_REG_DATA_CMD, last);
278                 last = 0;
279         }
280
281         /*
282          * If writing and not told otherwise, issue the write count (smbus).
283          */
284         if (wcount && (op & SMB_TRANS_NOCNT) == 0) {
285                 error = wait_status(sc, IG4_STATUS_TX_NOTFULL);
286                 if (error)
287                         goto done;
288                 last |= (u_char)cmd;
289                 reg_write(sc, IG4_REG_DATA_CMD, last);
290                 last = 0;
291         }
292
293         /*
294          * Bulk write (i2c)
295          */
296         while (wcount) {
297                 error = wait_status(sc, IG4_STATUS_TX_NOTFULL);
298                 if (error)
299                         goto done;
300                 last |= (u_char)*wbuf;
301                 if (wcount == 1 && rcount == 0 && (op & SMB_TRANS_NOSTOP) == 0)
302                         last |= IG4_DATA_STOP;
303                 reg_write(sc, IG4_REG_DATA_CMD, last);
304                 --wcount;
305                 ++wbuf;
306                 last = 0;
307         }
308
309         /*
310          * Issue reads to xmit FIFO (strange, I know) to tell the controller
311          * to clock in data.  At the moment just issue one read ahead to
312          * pipeline the incoming data.
313          *
314          * NOTE: In the case of NOCMD and wcount == 0 we still issue a
315          *       RESTART here, even if the data direction has not changed
316          *       from the previous CHAINing call.  This we force the RESTART.
317          *       (A new START is issued automatically by the controller in
318          *       the other nominal cases such as a data direction change or
319          *       a previous STOP was issued).
320          *
321          * If this will be the last byte read we must also issue the STOP
322          * at the end of the read.
323          */
324         if (rcount) {
325                 last = IG4_DATA_RESTART | IG4_DATA_COMMAND_RD;
326                 if (rcount == 1 &&
327                     (op & (SMB_TRANS_NOSTOP | SMB_TRANS_NOCNT)) ==
328                     SMB_TRANS_NOCNT) {
329                         last |= IG4_DATA_STOP;
330                 }
331                 reg_write(sc, IG4_REG_DATA_CMD, last);
332                 last = IG4_DATA_COMMAND_RD;
333         }
334
335         /*
336          * Bulk read (i2c) and count field handling (smbus)
337          */
338         while (rcount) {
339                 /*
340                  * Maintain a pipeline by queueing the allowance for the next
341                  * read before waiting for the current read.
342                  */
343                 if (rcount > 1) {
344                         if (op & SMB_TRANS_NOCNT)
345                                 last = (rcount == 2) ? IG4_DATA_STOP : 0;
346                         else
347                                 last = 0;
348                         reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_COMMAND_RD |
349                                                         last);
350                 }
351                 error = wait_status(sc, IG4_STATUS_RX_NOTEMPTY);
352                 if (error)
353                         goto done;
354                 last = reg_read(sc, IG4_REG_DATA_CMD);
355
356                 if (op & SMB_TRANS_NOCNT) {
357                         *rbuf = (u_char)last;
358                         ++rbuf;
359                         --rcount;
360                         if (actualp)
361                                 ++*actualp;
362                 } else {
363                         /*
364                          * Handle count field (smbus), which is not part of
365                          * the rcount'ed buffer.  The first read data in a
366                          * bulk transfer is the count.
367                          *
368                          * XXX if rcount is loaded as 0 how do I generate a
369                          *     STOP now without issuing another RD or WR?
370                          */
371                         if (rcount > (u_char)last)
372                                 rcount = (u_char)last;
373                         op |= SMB_TRANS_NOCNT;
374                 }
375         }
376         error = 0;
377 done:
378         /* XXX wait for xmit buffer to become empty */
379         last = reg_read(sc, IG4_REG_TX_ABRT_SOURCE);
380
381         return error;
382 }
383
384 /*
385  *                              SMBUS API FUNCTIONS
386  *
387  * Called from ig4iic_pci_attach/detach()
388  */
389 int
390 ig4iic_attach(ig4iic_softc_t *sc)
391 {
392         int error;
393         uint32_t v;
394
395         lockmgr(&sc->lk, LK_EXCLUSIVE);
396
397         v = reg_read(sc, IG4_REG_COMP_TYPE);
398         kprintf("type %08x\n", v);
399         v = reg_read(sc, IG4_REG_COMP_PARAM1);
400         kprintf("params %08x\n", v);
401         v = reg_read(sc, IG4_REG_COMP_VER);
402         kprintf("version %08x\n", v);
403         if (v != IG4_COMP_VER) {
404                 error = ENXIO;
405                 goto done;
406         }
407 #if 1
408         v = reg_read(sc, IG4_REG_SS_SCL_HCNT);
409         kprintf("SS_SCL_HCNT %08x\n", v);
410         v = reg_read(sc, IG4_REG_SS_SCL_LCNT);
411         kprintf("SS_SCL_LCNT %08x\n", v);
412         v = reg_read(sc, IG4_REG_FS_SCL_HCNT);
413         kprintf("FS_SCL_HCNT %08x\n", v);
414         v = reg_read(sc, IG4_REG_FS_SCL_LCNT);
415         kprintf("FS_SCL_LCNT %08x\n", v);
416         v = reg_read(sc, IG4_REG_SDA_HOLD);
417         kprintf("HOLD        %08x\n", v);
418
419         v = reg_read(sc, IG4_REG_SS_SCL_HCNT);
420         reg_write(sc, IG4_REG_FS_SCL_HCNT, v);
421         v = reg_read(sc, IG4_REG_SS_SCL_LCNT);
422         reg_write(sc, IG4_REG_FS_SCL_LCNT, v);
423 #endif
424         /*
425          * Program based on a 25000 Hz clock.  This is a bit of a
426          * hack (obviously).  The defaults are 400 and 470 for standard
427          * and 60 and 130 for fast.  The defaults for standard fail
428          * utterly (presumably cause an abort) because the clock time
429          * is ~18.8ms by default.  This brings it down to ~4ms (for now).
430          */
431         reg_write(sc, IG4_REG_SS_SCL_HCNT, 100);
432         reg_write(sc, IG4_REG_SS_SCL_LCNT, 125);
433         reg_write(sc, IG4_REG_FS_SCL_HCNT, 100);
434         reg_write(sc, IG4_REG_FS_SCL_LCNT, 125);
435
436         /*
437          * Use a threshold of 1 so we get interrupted on each character,
438          * allowing us to use lksleep() in our poll code.  Not perfect
439          * but this is better than using DELAY() for receiving data.
440          */
441         reg_write(sc, IG4_REG_RX_TL, 1);
442
443         reg_write(sc, IG4_REG_CTL,
444                   IG4_CTL_MASTER |
445                   IG4_CTL_SLAVE_DISABLE |
446                   IG4_CTL_RESTARTEN |
447                   IG4_CTL_SPEED_STD);
448
449         sc->smb = device_add_child(sc->dev, "smbus", -1);
450         if (sc->smb == NULL) {
451                 device_printf(sc->dev, "smbus driver not found\n");
452                 error = ENXIO;
453                 goto done;
454         }
455
456 #if 0
457         /*
458          * Don't do this, it blows up the PCI config
459          */
460         reg_write(sc, IG4_REG_RESETS, IG4_RESETS_ASSERT);
461         reg_write(sc, IG4_REG_RESETS, IG4_RESETS_DEASSERT);
462 #endif
463
464         /*
465          * Interrupt on STOP detect or receive character ready
466          */
467         reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET |
468                                          IG4_INTR_RX_FULL);
469         if (set_controller(sc, 0))
470                 device_printf(sc->dev, "controller error during attach-1\n");
471         if (set_controller(sc, IG4_I2C_ENABLE))
472                 device_printf(sc->dev, "controller error during attach-2\n");
473         error = bus_setup_intr(sc->dev, sc->intr_res, 0,
474                                ig4iic_intr, sc, &sc->intr_handle, NULL);
475         if (error) {
476                 device_printf(sc->dev,
477                               "Unable to setup irq: error %d\n", error);
478                 goto done;
479         }
480
481         /* Attach us to the smbus */
482         lockmgr(&sc->lk, LK_RELEASE);
483         error = bus_generic_attach(sc->dev);
484         lockmgr(&sc->lk, LK_EXCLUSIVE);
485         if (error) {
486                 device_printf(sc->dev,
487                               "failed to attach child: error %d\n", error);
488                 goto done;
489         }
490         sc->generic_attached = 1;
491
492 done:
493         lockmgr(&sc->lk, LK_RELEASE);
494         return error;
495 }
496
497 int
498 ig4iic_detach(ig4iic_softc_t *sc)
499 {
500         int error;
501
502         lockmgr(&sc->lk, LK_EXCLUSIVE);
503
504         reg_write(sc, IG4_REG_INTR_MASK, 0);
505         reg_read(sc, IG4_REG_CLR_INTR);
506         set_controller(sc, 0);
507
508         if (sc->generic_attached) {
509                 error = bus_generic_detach(sc->dev);
510                 if (error)
511                         goto done;
512                 sc->generic_attached = 0;
513         }
514         if (sc->smb) {
515                 device_delete_child(sc->dev, sc->smb);
516                 sc->smb = NULL;
517         }
518         if (sc->intr_handle) {
519                 bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle);
520                 sc->intr_handle = NULL;
521         }
522
523         error = 0;
524 done:
525         lockmgr(&sc->lk, LK_RELEASE);
526         return error;
527 }
528
529 int
530 ig4iic_smb_callback(device_t dev, int index, void *data)
531 {
532         ig4iic_softc_t *sc = device_get_softc(dev);
533         int error;
534
535         lockmgr(&sc->lk, LK_EXCLUSIVE);
536
537         switch (index) {
538         case SMB_REQUEST_BUS:
539                 error = 0;
540                 break;
541         case SMB_RELEASE_BUS:
542                 error = 0;
543                 break;
544         default:
545                 error = SMB_EABORT;
546                 break;
547         }
548
549         lockmgr(&sc->lk, LK_RELEASE);
550
551         return error;
552 }
553
554 /*
555  * Quick command.  i.e. START + cmd + R/W + STOP and no data.  It is
556  * unclear to me how I could implement this with the intel i2c controller
557  * because the controler sends STARTs and STOPs automatically with data.
558  */
559 int
560 ig4iic_smb_quick(device_t dev, u_char slave, int how)
561 {
562         ig4iic_softc_t *sc = device_get_softc(dev);
563         int error;
564
565         lockmgr(&sc->lk, LK_EXCLUSIVE);
566
567         switch (how) {
568         case SMB_QREAD:
569                 error = SMB_ENOTSUPP;
570                 break;
571         case SMB_QWRITE:
572                 error = SMB_ENOTSUPP;
573                 break;
574         default:
575                 error = SMB_ENOTSUPP;
576                 break;
577         }
578         lockmgr(&sc->lk, LK_RELEASE);
579
580         return error;
581 }
582
583 /*
584  * Incremental send byte without stop (?).  It is unclear why the slave
585  * address is specified if this presumably is used in combination with
586  * ig4iic_smb_quick().
587  *
588  * (Also, how would this work anyway?  Issue the last byte with writeb()?)
589  */
590 int
591 ig4iic_smb_sendb(device_t dev, u_char slave, char byte)
592 {
593         ig4iic_softc_t *sc = device_get_softc(dev);
594         uint32_t cmd;
595         int error;
596
597         lockmgr(&sc->lk, LK_EXCLUSIVE);
598
599         set_slave_addr(sc, slave, 0);
600         cmd = byte;
601         if (wait_status(sc, IG4_STATUS_TX_NOTFULL) == 0) {
602                 reg_write(sc, IG4_REG_DATA_CMD, cmd);
603                 error = 0;
604         } else {
605                 error = SMB_ETIMEOUT;
606         }
607
608         lockmgr(&sc->lk, LK_RELEASE);
609         return error;
610 }
611
612 /*
613  * Incremental receive byte without stop (?).  It is unclear why the slave
614  * address is specified if this presumably is used in combination with
615  * ig4iic_smb_quick().
616  */
617 int
618 ig4iic_smb_recvb(device_t dev, u_char slave, char *byte)
619 {
620         ig4iic_softc_t *sc = device_get_softc(dev);
621         int error;
622
623         lockmgr(&sc->lk, LK_EXCLUSIVE);
624
625         set_slave_addr(sc, slave, 0);
626         reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_COMMAND_RD);
627         if (wait_status(sc, IG4_STATUS_RX_NOTEMPTY) == 0) {
628                 *byte = (uint8_t)reg_read(sc, IG4_REG_DATA_CMD);
629                 error = 0;
630         } else {
631                 *byte = 0;
632                 error = SMB_ETIMEOUT;
633         }
634
635         lockmgr(&sc->lk, LK_RELEASE);
636         return error;
637 }
638
639 /*
640  * Write command and single byte in transaction.
641  */
642 int
643 ig4iic_smb_writeb(device_t dev, u_char slave, char cmd, char byte)
644 {
645         ig4iic_softc_t *sc = device_get_softc(dev);
646         int error;
647
648         lockmgr(&sc->lk, LK_EXCLUSIVE);
649
650         set_slave_addr(sc, slave, 0);
651         error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
652                                 &byte, 1, NULL, 0, NULL);
653
654         lockmgr(&sc->lk, LK_RELEASE);
655         return error;
656 }
657
658 /*
659  * Write command and single word in transaction.
660  */
661 int
662 ig4iic_smb_writew(device_t dev, u_char slave, char cmd, short word)
663 {
664         ig4iic_softc_t *sc = device_get_softc(dev);
665         char buf[2];
666         int error;
667
668         lockmgr(&sc->lk, LK_EXCLUSIVE);
669
670         set_slave_addr(sc, slave, 0);
671         buf[0] = word & 0xFF;
672         buf[1] = word >> 8;
673         error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
674                                 buf, 2, NULL, 0, NULL);
675
676         lockmgr(&sc->lk, LK_RELEASE);
677         return error;
678 }
679
680 /*
681  * write command and read single byte in transaction.
682  */
683 int
684 ig4iic_smb_readb(device_t dev, u_char slave, char cmd, char *byte)
685 {
686         ig4iic_softc_t *sc = device_get_softc(dev);
687         int error;
688
689         lockmgr(&sc->lk, LK_EXCLUSIVE);
690
691         set_slave_addr(sc, slave, 0);
692         error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
693                                 NULL, 0, byte, 1, NULL);
694
695         lockmgr(&sc->lk, LK_RELEASE);
696         return error;
697 }
698
699 /*
700  * write command and read word in transaction.
701  */
702 int
703 ig4iic_smb_readw(device_t dev, u_char slave, char cmd, short *word)
704 {
705         ig4iic_softc_t *sc = device_get_softc(dev);
706         char buf[2];
707         int error;
708
709         lockmgr(&sc->lk, LK_EXCLUSIVE);
710
711         set_slave_addr(sc, slave, 0);
712         if ((error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
713                                      NULL, 0, buf, 2, NULL)) == 0) {
714                 *word = (u_char)buf[0] | ((u_char)buf[1] << 8);
715         }
716
717         lockmgr(&sc->lk, LK_RELEASE);
718         return error;
719 }
720
721 /*
722  * write command and word and read word in transaction
723  */
724 int
725 ig4iic_smb_pcall(device_t dev, u_char slave, char cmd,
726                  short sdata, short *rdata)
727 {
728         ig4iic_softc_t *sc = device_get_softc(dev);
729         char rbuf[2];
730         char wbuf[2];
731         int error;
732
733         lockmgr(&sc->lk, LK_EXCLUSIVE);
734
735         set_slave_addr(sc, slave, 0);
736         wbuf[0] = sdata & 0xFF;
737         wbuf[1] = sdata >> 8;
738         if ((error = smb_transaction(sc, cmd, SMB_TRANS_NOCNT,
739                                      wbuf, 2, rbuf, 2, NULL)) == 0) {
740                 *rdata = (u_char)rbuf[0] | ((u_char)rbuf[1] << 8);
741         }
742
743         lockmgr(&sc->lk, LK_RELEASE);
744         return error;
745 }
746
747 int
748 ig4iic_smb_bwrite(device_t dev, u_char slave, char cmd,
749                   u_char wcount, char *buf)
750 {
751         ig4iic_softc_t *sc = device_get_softc(dev);
752         int error;
753
754         lockmgr(&sc->lk, LK_EXCLUSIVE);
755
756         set_slave_addr(sc, slave, 0);
757         error = smb_transaction(sc, cmd, 0,
758                                 buf, wcount, NULL, 0, NULL);
759
760         lockmgr(&sc->lk, LK_RELEASE);
761         return error;
762 }
763
764 int
765 ig4iic_smb_bread(device_t dev, u_char slave, char cmd,
766                  u_char *countp_char, char *buf)
767 {
768         ig4iic_softc_t *sc = device_get_softc(dev);
769         int rcount = *countp_char;
770         int error;
771
772         lockmgr(&sc->lk, LK_EXCLUSIVE);
773
774         set_slave_addr(sc, slave, 0);
775         error = smb_transaction(sc, cmd, 0,
776                                 NULL, 0, buf, rcount, &rcount);
777         *countp_char = rcount;
778
779         lockmgr(&sc->lk, LK_RELEASE);
780         return error;
781 }
782
783 int
784 ig4iic_smb_trans(device_t dev, int slave, char cmd, int op,
785                  char *wbuf, int wcount, char *rbuf, int rcount,
786                  int *actualp)
787 {
788         ig4iic_softc_t *sc = device_get_softc(dev);
789         int error;
790
791         lockmgr(&sc->lk, LK_EXCLUSIVE);
792
793         set_slave_addr(sc, slave, op);
794         error = smb_transaction(sc, cmd, op,
795                                 wbuf, wcount, rbuf, rcount, actualp);
796
797         lockmgr(&sc->lk, LK_RELEASE);
798         return error;
799 }
800
801 /*
802  * Interrupt Operation
803  */
804 static
805 void
806 ig4iic_intr(void *cookie)
807 {
808         ig4iic_softc_t *sc = cookie;
809
810         lockmgr(&sc->lk, LK_EXCLUSIVE);
811 /*      reg_write(sc, IG4_REG_INTR_MASK, IG4_INTR_STOP_DET);*/
812         reg_read(sc, IG4_REG_CLR_INTR);
813         wakeup(sc);
814         lockmgr(&sc->lk, LK_RELEASE);
815 }
816
817 DRIVER_MODULE(smbus, ig4iic, smbus_driver, smbus_devclass, NULL, NULL);