2 * Copyright (c) 1998 Nicolas Souchu
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $FreeBSD: src/sys/dev/iicbus/iicsmb.c,v 1.5.2.2 2000/08/09 00:59:27 peter Exp $
27 * $DragonFly: src/sys/bus/iicbus/iicsmb.c,v 1.5 2006/12/22 23:12:16 swildner Exp $
49 #include <sys/param.h>
50 #include <sys/kernel.h>
51 #include <sys/systm.h>
52 #include <sys/module.h>
57 #include <sys/malloc.h>
59 #include <machine/clock.h>
64 #include <bus/smbus/smbconf.h>
66 #include "iicbus_if.h"
71 #define SMB_WAITING_ADDR 0x0
72 #define SMB_WAITING_LOW 0x1
73 #define SMB_WAITING_HIGH 0x2
77 u_char devaddr
; /* slave device address */
79 char low
; /* low byte received first */
80 char high
; /* high byte */
85 static int iicsmb_probe(device_t
);
86 static int iicsmb_attach(device_t
);
88 static void iicsmb_intr(device_t dev
, int event
, char *buf
);
89 static int iicsmb_callback(device_t dev
, int index
, caddr_t data
);
90 static int iicsmb_quick(device_t dev
, u_char slave
, int how
);
91 static int iicsmb_sendb(device_t dev
, u_char slave
, char byte
);
92 static int iicsmb_recvb(device_t dev
, u_char slave
, char *byte
);
93 static int iicsmb_writeb(device_t dev
, u_char slave
, char cmd
, char byte
);
94 static int iicsmb_writew(device_t dev
, u_char slave
, char cmd
, short word
);
95 static int iicsmb_readb(device_t dev
, u_char slave
, char cmd
, char *byte
);
96 static int iicsmb_readw(device_t dev
, u_char slave
, char cmd
, short *word
);
97 static int iicsmb_pcall(device_t dev
, u_char slave
, char cmd
, short sdata
, short *rdata
);
98 static int iicsmb_bwrite(device_t dev
, u_char slave
, char cmd
, u_char count
, char *buf
);
99 static int iicsmb_bread(device_t dev
, u_char slave
, char cmd
, u_char count
, char *buf
);
101 static devclass_t iicsmb_devclass
;
103 static device_method_t iicsmb_methods
[] = {
104 /* device interface */
105 DEVMETHOD(device_probe
, iicsmb_probe
),
106 DEVMETHOD(device_attach
, iicsmb_attach
),
107 DEVMETHOD(device_detach
, bus_generic_detach
),
110 DEVMETHOD(bus_print_child
, bus_generic_print_child
),
112 /* iicbus interface */
113 DEVMETHOD(iicbus_intr
, iicsmb_intr
),
115 /* smbus interface */
116 DEVMETHOD(smbus_callback
, iicsmb_callback
),
117 DEVMETHOD(smbus_quick
, iicsmb_quick
),
118 DEVMETHOD(smbus_sendb
, iicsmb_sendb
),
119 DEVMETHOD(smbus_recvb
, iicsmb_recvb
),
120 DEVMETHOD(smbus_writeb
, iicsmb_writeb
),
121 DEVMETHOD(smbus_writew
, iicsmb_writew
),
122 DEVMETHOD(smbus_readb
, iicsmb_readb
),
123 DEVMETHOD(smbus_readw
, iicsmb_readw
),
124 DEVMETHOD(smbus_pcall
, iicsmb_pcall
),
125 DEVMETHOD(smbus_bwrite
, iicsmb_bwrite
),
126 DEVMETHOD(smbus_bread
, iicsmb_bread
),
131 static driver_t iicsmb_driver
= {
134 sizeof(struct iicsmb_softc
),
138 iicsmb_probe(device_t dev
)
140 struct iicsmb_softc
*sc
= (struct iicsmb_softc
*)device_get_softc(dev
);
142 sc
->smbus
= smbus_alloc_bus(dev
);
145 return (EINVAL
); /* XXX don't know what to return else */
151 iicsmb_attach(device_t dev
)
153 struct iicsmb_softc
*sc
= (struct iicsmb_softc
*)device_get_softc(dev
);
155 /* probe and attach the smbus */
156 device_probe_and_attach(sc
->smbus
);
164 * iicbus interrupt handler
167 iicsmb_intr(device_t dev
, int event
, char *buf
)
169 struct iicsmb_softc
*sc
= (struct iicsmb_softc
*)device_get_softc(dev
);
174 sc
->state
= SMB_WAITING_ADDR
;
178 /* call smbus intr handler */
179 smbus_intr(sc
->smbus
, sc
->devaddr
,
180 sc
->low
, sc
->high
, SMB_ENOERR
);
186 /* XXX too much data, discard */
187 kprintf("%s: too much data from 0x%x\n", __func__
,
191 case SMB_WAITING_ADDR
:
192 sc
->devaddr
= (u_char
)*buf
;
193 sc
->state
= SMB_WAITING_LOW
;
196 case SMB_WAITING_LOW
:
198 sc
->state
= SMB_WAITING_HIGH
;
201 case SMB_WAITING_HIGH
:
203 sc
->state
= SMB_DONE
;
216 smbus_intr(sc
->smbus
, sc
->devaddr
, 0, 0, SMB_EBUSERR
);
220 kprintf("%s unknown error 0x%x!\n", __func__
,
227 panic("%s: unknown event (%d)!", __func__
, event
);
234 iicsmb_callback(device_t dev
, int index
, caddr_t data
)
236 device_t parent
= device_get_parent(dev
);
241 case SMB_REQUEST_BUS
:
242 /* request underlying iicbus */
244 error
= iicbus_request_bus(parent
, dev
, how
);
247 case SMB_RELEASE_BUS
:
248 /* release underlying iicbus */
249 error
= iicbus_release_bus(parent
, dev
);
260 iicsmb_quick(device_t dev
, u_char slave
, int how
)
262 device_t parent
= device_get_parent(dev
);
267 error
= iicbus_start(parent
, slave
& ~LSB
, 0);
271 error
= iicbus_start(parent
, slave
| LSB
, 0);
280 error
= iicbus_stop(parent
);
286 iicsmb_sendb(device_t dev
, u_char slave
, char byte
)
288 device_t parent
= device_get_parent(dev
);
291 error
= iicbus_start(parent
, slave
& ~LSB
, 0);
294 error
= iicbus_write(parent
, &byte
, 1, &sent
, 0);
303 iicsmb_recvb(device_t dev
, u_char slave
, char *byte
)
305 device_t parent
= device_get_parent(dev
);
308 error
= iicbus_start(parent
, slave
| LSB
, 0);
311 error
= iicbus_read(parent
, byte
, 1, &read
, IIC_LAST_READ
, 0);
320 iicsmb_writeb(device_t dev
, u_char slave
, char cmd
, char byte
)
322 device_t parent
= device_get_parent(dev
);
325 error
= iicbus_start(parent
, slave
& ~LSB
, 0);
328 if (!(error
= iicbus_write(parent
, &cmd
, 1, &sent
, 0)))
329 error
= iicbus_write(parent
, &byte
, 1, &sent
, 0);
338 iicsmb_writew(device_t dev
, u_char slave
, char cmd
, short word
)
340 device_t parent
= device_get_parent(dev
);
343 char low
= (char)(word
& 0xff);
344 char high
= (char)((word
& 0xff00) >> 8);
346 error
= iicbus_start(parent
, slave
& ~LSB
, 0);
349 if (!(error
= iicbus_write(parent
, &cmd
, 1, &sent
, 0)))
350 if (!(error
= iicbus_write(parent
, &low
, 1, &sent
, 0)))
351 error
= iicbus_write(parent
, &high
, 1, &sent
, 0);
360 iicsmb_readb(device_t dev
, u_char slave
, char cmd
, char *byte
)
362 device_t parent
= device_get_parent(dev
);
363 int error
, sent
, read
;
365 if ((error
= iicbus_start(parent
, slave
& ~LSB
, 0)))
368 if ((error
= iicbus_write(parent
, &cmd
, 1, &sent
, 0)))
371 if ((error
= iicbus_repeated_start(parent
, slave
| LSB
, 0)))
374 if ((error
= iicbus_read(parent
, byte
, 1, &read
, IIC_LAST_READ
, 0)))
382 #define BUF2SHORT(low,high) \
383 ((short)(((high) & 0xff) << 8) | (short)((low) & 0xff))
386 iicsmb_readw(device_t dev
, u_char slave
, char cmd
, short *word
)
388 device_t parent
= device_get_parent(dev
);
389 int error
, sent
, read
;
392 if ((error
= iicbus_start(parent
, slave
& ~LSB
, 0)))
395 if ((error
= iicbus_write(parent
, &cmd
, 1, &sent
, 0)))
398 if ((error
= iicbus_repeated_start(parent
, slave
| LSB
, 0)))
401 if ((error
= iicbus_read(parent
, buf
, 2, &read
, IIC_LAST_READ
, 0)))
404 /* first, receive low, then high byte */
405 *word
= BUF2SHORT(buf
[0], buf
[1]);
413 iicsmb_pcall(device_t dev
, u_char slave
, char cmd
, short sdata
, short *rdata
)
415 device_t parent
= device_get_parent(dev
);
416 int error
, sent
, read
;
419 if ((error
= iicbus_start(parent
, slave
& ~LSB
, 0)))
422 if ((error
= iicbus_write(parent
, &cmd
, 1, &sent
, 0)))
425 /* first, send low, then high byte */
426 buf
[0] = (char)(sdata
& 0xff);
427 buf
[1] = (char)((sdata
& 0xff00) >> 8);
429 if ((error
= iicbus_write(parent
, buf
, 2, &sent
, 0)))
432 if ((error
= iicbus_repeated_start(parent
, slave
| LSB
, 0)))
435 if ((error
= iicbus_read(parent
, buf
, 2, &read
, IIC_LAST_READ
, 0)))
438 /* first, receive low, then high byte */
439 *rdata
= BUF2SHORT(buf
[0], buf
[1]);
447 iicsmb_bwrite(device_t dev
, u_char slave
, char cmd
, u_char count
, char *buf
)
449 device_t parent
= device_get_parent(dev
);
452 if ((error
= iicbus_start(parent
, slave
& ~LSB
, 0)))
455 if ((error
= iicbus_write(parent
, &cmd
, 1, &sent
, 0)))
458 if ((error
= iicbus_write(parent
, buf
, (int)count
, &sent
, 0)))
461 if ((error
= iicbus_stop(parent
)))
469 iicsmb_bread(device_t dev
, u_char slave
, char cmd
, u_char count
, char *buf
)
471 device_t parent
= device_get_parent(dev
);
472 int error
, sent
, read
;
474 if ((error
= iicbus_start(parent
, slave
& ~LSB
, 0)))
477 if ((error
= iicbus_write(parent
, &cmd
, 1, &sent
, 0)))
480 if ((error
= iicbus_repeated_start(parent
, slave
| LSB
, 0)))
483 if ((error
= iicbus_read(parent
, buf
, (int)count
, &read
,
492 DRIVER_MODULE(iicsmb
, iicbus
, iicsmb_driver
, iicsmb_devclass
, 0, 0);