1c3e2dc6bSNicolas Souchu /*- 2c3e2dc6bSNicolas Souchu * Copyright (c) 1998 Nicolas Souchu 3c3e2dc6bSNicolas Souchu * All rights reserved. 4c3e2dc6bSNicolas Souchu * 5c3e2dc6bSNicolas Souchu * Redistribution and use in source and binary forms, with or without 6c3e2dc6bSNicolas Souchu * modification, are permitted provided that the following conditions 7c3e2dc6bSNicolas Souchu * are met: 8c3e2dc6bSNicolas Souchu * 1. Redistributions of source code must retain the above copyright 9c3e2dc6bSNicolas Souchu * notice, this list of conditions and the following disclaimer. 10c3e2dc6bSNicolas Souchu * 2. Redistributions in binary form must reproduce the above copyright 11c3e2dc6bSNicolas Souchu * notice, this list of conditions and the following disclaimer in the 12c3e2dc6bSNicolas Souchu * documentation and/or other materials provided with the distribution. 13c3e2dc6bSNicolas Souchu * 14c3e2dc6bSNicolas Souchu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c3e2dc6bSNicolas Souchu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c3e2dc6bSNicolas Souchu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c3e2dc6bSNicolas Souchu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c3e2dc6bSNicolas Souchu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c3e2dc6bSNicolas Souchu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c3e2dc6bSNicolas Souchu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c3e2dc6bSNicolas Souchu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c3e2dc6bSNicolas Souchu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c3e2dc6bSNicolas Souchu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c3e2dc6bSNicolas Souchu * SUCH DAMAGE. 25c3e2dc6bSNicolas Souchu * 2604f89a63SNicolas Souchu * $Id: iicsmb.c,v 1.1.1.1 1998/09/03 20:51:50 nsouch Exp $ 27c3e2dc6bSNicolas Souchu * 28c3e2dc6bSNicolas Souchu */ 29c3e2dc6bSNicolas Souchu 30c3e2dc6bSNicolas Souchu /* 31c3e2dc6bSNicolas Souchu * I2C to SMB bridge 3204f89a63SNicolas Souchu * 3304f89a63SNicolas Souchu * Example: 3404f89a63SNicolas Souchu * 3504f89a63SNicolas Souchu * smb bttv 3604f89a63SNicolas Souchu * \ / 3704f89a63SNicolas Souchu * smbus 3804f89a63SNicolas Souchu * / \ 3904f89a63SNicolas Souchu * iicsmb bti2c 4004f89a63SNicolas Souchu * | 4104f89a63SNicolas Souchu * iicbus 4204f89a63SNicolas Souchu * / | \ 4304f89a63SNicolas Souchu * iicbb pcf ... 4404f89a63SNicolas Souchu * | 4504f89a63SNicolas Souchu * lpbb 46c3e2dc6bSNicolas Souchu */ 47c3e2dc6bSNicolas Souchu 48c3e2dc6bSNicolas Souchu #include <sys/param.h> 49c3e2dc6bSNicolas Souchu #include <sys/kernel.h> 50c3e2dc6bSNicolas Souchu #include <sys/systm.h> 51c3e2dc6bSNicolas Souchu #include <sys/module.h> 52c3e2dc6bSNicolas Souchu #include <sys/bus.h> 53c3e2dc6bSNicolas Souchu #include <sys/conf.h> 54c3e2dc6bSNicolas Souchu #include <sys/buf.h> 55c3e2dc6bSNicolas Souchu #include <sys/uio.h> 56c3e2dc6bSNicolas Souchu #include <sys/malloc.h> 57c3e2dc6bSNicolas Souchu 58c3e2dc6bSNicolas Souchu #include <machine/clock.h> 59c3e2dc6bSNicolas Souchu 60c3e2dc6bSNicolas Souchu #include <dev/iicbus/iiconf.h> 61c3e2dc6bSNicolas Souchu #include <dev/iicbus/iicbus.h> 62c3e2dc6bSNicolas Souchu 63c3e2dc6bSNicolas Souchu #include <dev/smbus/smbconf.h> 64c3e2dc6bSNicolas Souchu 65c3e2dc6bSNicolas Souchu #include "iicbus_if.h" 66c3e2dc6bSNicolas Souchu #include "smbus_if.h" 67c3e2dc6bSNicolas Souchu 68c3e2dc6bSNicolas Souchu struct iicsmb_softc { 69c3e2dc6bSNicolas Souchu 70c3e2dc6bSNicolas Souchu #define SMB_WAITING_ADDR 0x0 71c3e2dc6bSNicolas Souchu #define SMB_WAITING_LOW 0x1 72c3e2dc6bSNicolas Souchu #define SMB_WAITING_HIGH 0x2 73c3e2dc6bSNicolas Souchu #define SMB_DONE 0x3 74c3e2dc6bSNicolas Souchu int state; 75c3e2dc6bSNicolas Souchu 76c3e2dc6bSNicolas Souchu u_char devaddr; /* slave device address */ 77c3e2dc6bSNicolas Souchu 78c3e2dc6bSNicolas Souchu char low; /* low byte received first */ 79c3e2dc6bSNicolas Souchu char high; /* high byte */ 80c3e2dc6bSNicolas Souchu 81c3e2dc6bSNicolas Souchu device_t smbus; 82c3e2dc6bSNicolas Souchu }; 83c3e2dc6bSNicolas Souchu 84c3e2dc6bSNicolas Souchu static int iicsmb_probe(device_t); 85c3e2dc6bSNicolas Souchu static int iicsmb_attach(device_t); 86c3e2dc6bSNicolas Souchu static void iicsmb_print_child(device_t, device_t); 87c3e2dc6bSNicolas Souchu 88c3e2dc6bSNicolas Souchu static void iicsmb_intr(device_t dev, int event, char *buf); 8904f89a63SNicolas Souchu static int iicsmb_callback(device_t dev, int index, caddr_t data); 90c3e2dc6bSNicolas Souchu static int iicsmb_quick(device_t dev, u_char slave, int how); 91c3e2dc6bSNicolas Souchu static int iicsmb_sendb(device_t dev, u_char slave, char byte); 92c3e2dc6bSNicolas Souchu static int iicsmb_recvb(device_t dev, u_char slave, char *byte); 93c3e2dc6bSNicolas Souchu static int iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 94c3e2dc6bSNicolas Souchu static int iicsmb_writew(device_t dev, u_char slave, char cmd, short word); 95c3e2dc6bSNicolas Souchu static int iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 96c3e2dc6bSNicolas Souchu static int iicsmb_readw(device_t dev, u_char slave, char cmd, short *word); 97c3e2dc6bSNicolas Souchu static int iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 98c3e2dc6bSNicolas Souchu static int iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 99c3e2dc6bSNicolas Souchu static int iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 100c3e2dc6bSNicolas Souchu 101c3e2dc6bSNicolas Souchu static devclass_t iicsmb_devclass; 102c3e2dc6bSNicolas Souchu 103c3e2dc6bSNicolas Souchu static device_method_t iicsmb_methods[] = { 104c3e2dc6bSNicolas Souchu /* device interface */ 105c3e2dc6bSNicolas Souchu DEVMETHOD(device_probe, iicsmb_probe), 106c3e2dc6bSNicolas Souchu DEVMETHOD(device_attach, iicsmb_attach), 107c3e2dc6bSNicolas Souchu 108c3e2dc6bSNicolas Souchu /* bus interface */ 109c3e2dc6bSNicolas Souchu DEVMETHOD(bus_print_child, iicsmb_print_child), 110c3e2dc6bSNicolas Souchu 111c3e2dc6bSNicolas Souchu /* iicbus interface */ 112c3e2dc6bSNicolas Souchu DEVMETHOD(iicbus_intr, iicsmb_intr), 113c3e2dc6bSNicolas Souchu 114c3e2dc6bSNicolas Souchu /* smbus interface */ 11504f89a63SNicolas Souchu DEVMETHOD(smbus_callback, iicsmb_callback), 116c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_quick, iicsmb_quick), 117c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_sendb, iicsmb_sendb), 118c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_recvb, iicsmb_recvb), 119c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_writeb, iicsmb_writeb), 120c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_writew, iicsmb_writew), 121c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_readb, iicsmb_readb), 122c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_readw, iicsmb_readw), 123c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_pcall, iicsmb_pcall), 124c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_bwrite, iicsmb_bwrite), 125c3e2dc6bSNicolas Souchu DEVMETHOD(smbus_bread, iicsmb_bread), 126c3e2dc6bSNicolas Souchu 127c3e2dc6bSNicolas Souchu { 0, 0 } 128c3e2dc6bSNicolas Souchu }; 129c3e2dc6bSNicolas Souchu 130c3e2dc6bSNicolas Souchu static driver_t iicsmb_driver = { 131c3e2dc6bSNicolas Souchu "iicsmb", 132c3e2dc6bSNicolas Souchu iicsmb_methods, 133c3e2dc6bSNicolas Souchu DRIVER_TYPE_MISC, 134c3e2dc6bSNicolas Souchu sizeof(struct iicsmb_softc), 135c3e2dc6bSNicolas Souchu }; 136c3e2dc6bSNicolas Souchu 137c3e2dc6bSNicolas Souchu static int 138c3e2dc6bSNicolas Souchu iicsmb_probe(device_t dev) 139c3e2dc6bSNicolas Souchu { 140c3e2dc6bSNicolas Souchu struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 141c3e2dc6bSNicolas Souchu 142c3e2dc6bSNicolas Souchu sc->smbus = smbus_alloc_bus(dev); 143c3e2dc6bSNicolas Souchu 144c3e2dc6bSNicolas Souchu if (!sc->smbus) 145c3e2dc6bSNicolas Souchu return (EINVAL); /* XXX don't know what to return else */ 146c3e2dc6bSNicolas Souchu 147c3e2dc6bSNicolas Souchu return (0); 148c3e2dc6bSNicolas Souchu } 149c3e2dc6bSNicolas Souchu 150c3e2dc6bSNicolas Souchu static int 151c3e2dc6bSNicolas Souchu iicsmb_attach(device_t dev) 152c3e2dc6bSNicolas Souchu { 153c3e2dc6bSNicolas Souchu struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 154c3e2dc6bSNicolas Souchu 155c3e2dc6bSNicolas Souchu /* probe and attach the smbus */ 156c3e2dc6bSNicolas Souchu device_probe_and_attach(sc->smbus); 157c3e2dc6bSNicolas Souchu 158c3e2dc6bSNicolas Souchu return (0); 159c3e2dc6bSNicolas Souchu } 160c3e2dc6bSNicolas Souchu 161c3e2dc6bSNicolas Souchu static void 162c3e2dc6bSNicolas Souchu iicsmb_print_child(device_t bus, device_t dev) 163c3e2dc6bSNicolas Souchu { 164c3e2dc6bSNicolas Souchu printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); 165c3e2dc6bSNicolas Souchu 166c3e2dc6bSNicolas Souchu return; 167c3e2dc6bSNicolas Souchu } 168c3e2dc6bSNicolas Souchu 169c3e2dc6bSNicolas Souchu /* 170c3e2dc6bSNicolas Souchu * iicsmb_intr() 171c3e2dc6bSNicolas Souchu * 172c3e2dc6bSNicolas Souchu * iicbus interrupt handler 173c3e2dc6bSNicolas Souchu */ 174c3e2dc6bSNicolas Souchu static void 175c3e2dc6bSNicolas Souchu iicsmb_intr(device_t dev, int event, char *buf) 176c3e2dc6bSNicolas Souchu { 177c3e2dc6bSNicolas Souchu struct iicsmb_softc *sc = (struct iicsmb_softc *)device_get_softc(dev); 178c3e2dc6bSNicolas Souchu 179c3e2dc6bSNicolas Souchu switch (event) { 180c3e2dc6bSNicolas Souchu case INTR_GENERAL: 181c3e2dc6bSNicolas Souchu case INTR_START: 182c3e2dc6bSNicolas Souchu sc->state = SMB_WAITING_ADDR; 183c3e2dc6bSNicolas Souchu break; 184c3e2dc6bSNicolas Souchu 185c3e2dc6bSNicolas Souchu case INTR_STOP: 186c3e2dc6bSNicolas Souchu /* call smbus intr handler */ 187c3e2dc6bSNicolas Souchu smbus_intr(sc->smbus, sc->devaddr, 188c3e2dc6bSNicolas Souchu sc->low, sc->high, SMB_ENOERR); 189c3e2dc6bSNicolas Souchu break; 190c3e2dc6bSNicolas Souchu 191c3e2dc6bSNicolas Souchu case INTR_RECEIVE: 192c3e2dc6bSNicolas Souchu switch (sc->state) { 193c3e2dc6bSNicolas Souchu case SMB_DONE: 194c3e2dc6bSNicolas Souchu /* XXX too much data, discard */ 195c3e2dc6bSNicolas Souchu printf("%s: too much data from 0x%x\n", __FUNCTION__, 196c3e2dc6bSNicolas Souchu sc->devaddr & 0xff); 197c3e2dc6bSNicolas Souchu goto end; 198c3e2dc6bSNicolas Souchu 199c3e2dc6bSNicolas Souchu case SMB_WAITING_ADDR: 200c3e2dc6bSNicolas Souchu sc->devaddr = (u_char)*buf; 201c3e2dc6bSNicolas Souchu sc->state = SMB_WAITING_LOW; 202c3e2dc6bSNicolas Souchu break; 203c3e2dc6bSNicolas Souchu 204c3e2dc6bSNicolas Souchu case SMB_WAITING_LOW: 205c3e2dc6bSNicolas Souchu sc->low = *buf; 206c3e2dc6bSNicolas Souchu sc->state = SMB_WAITING_HIGH; 207c3e2dc6bSNicolas Souchu break; 208c3e2dc6bSNicolas Souchu 209c3e2dc6bSNicolas Souchu case SMB_WAITING_HIGH: 210c3e2dc6bSNicolas Souchu sc->high = *buf; 211c3e2dc6bSNicolas Souchu sc->state = SMB_DONE; 212c3e2dc6bSNicolas Souchu break; 213c3e2dc6bSNicolas Souchu } 214c3e2dc6bSNicolas Souchu end: 215c3e2dc6bSNicolas Souchu break; 216c3e2dc6bSNicolas Souchu 217c3e2dc6bSNicolas Souchu case INTR_TRANSMIT: 218c3e2dc6bSNicolas Souchu case INTR_NOACK: 219c3e2dc6bSNicolas Souchu break; 220c3e2dc6bSNicolas Souchu 221c3e2dc6bSNicolas Souchu case INTR_ERROR: 222c3e2dc6bSNicolas Souchu switch (*buf) { 223c3e2dc6bSNicolas Souchu case IIC_EBUSERR: 224c3e2dc6bSNicolas Souchu smbus_intr(sc->smbus, sc->devaddr, 0, 0, SMB_EBUSERR); 225c3e2dc6bSNicolas Souchu break; 226c3e2dc6bSNicolas Souchu 227c3e2dc6bSNicolas Souchu default: 228c3e2dc6bSNicolas Souchu printf("%s unknown error 0x%x!\n", __FUNCTION__, 229c3e2dc6bSNicolas Souchu (int)*buf); 230c3e2dc6bSNicolas Souchu break; 231c3e2dc6bSNicolas Souchu } 232c3e2dc6bSNicolas Souchu break; 233c3e2dc6bSNicolas Souchu 234c3e2dc6bSNicolas Souchu default: 235c3e2dc6bSNicolas Souchu panic("%s: unknown event (%d)!", __FUNCTION__, event); 236c3e2dc6bSNicolas Souchu } 237c3e2dc6bSNicolas Souchu 238c3e2dc6bSNicolas Souchu return; 239c3e2dc6bSNicolas Souchu } 240c3e2dc6bSNicolas Souchu 241c3e2dc6bSNicolas Souchu static int 24204f89a63SNicolas Souchu iicsmb_callback(device_t dev, int index, caddr_t data) 24304f89a63SNicolas Souchu { 24404f89a63SNicolas Souchu device_t parent = device_get_parent(dev); 24504f89a63SNicolas Souchu int error = 0; 24604f89a63SNicolas Souchu int how; 24704f89a63SNicolas Souchu 24804f89a63SNicolas Souchu switch (index) { 24904f89a63SNicolas Souchu case SMB_REQUEST_BUS: 25004f89a63SNicolas Souchu /* request underlying iicbus */ 25104f89a63SNicolas Souchu how = *(int *)data; 25204f89a63SNicolas Souchu error = iicbus_request_bus(parent, dev, how); 25304f89a63SNicolas Souchu break; 25404f89a63SNicolas Souchu 25504f89a63SNicolas Souchu case SMB_RELEASE_BUS: 25604f89a63SNicolas Souchu /* release underlying iicbus */ 25704f89a63SNicolas Souchu error = iicbus_release_bus(parent, dev); 25804f89a63SNicolas Souchu break; 25904f89a63SNicolas Souchu 26004f89a63SNicolas Souchu default: 26104f89a63SNicolas Souchu error = EINVAL; 26204f89a63SNicolas Souchu } 26304f89a63SNicolas Souchu 26404f89a63SNicolas Souchu return (error); 26504f89a63SNicolas Souchu } 26604f89a63SNicolas Souchu 26704f89a63SNicolas Souchu static int 268c3e2dc6bSNicolas Souchu iicsmb_quick(device_t dev, u_char slave, int how) 269c3e2dc6bSNicolas Souchu { 270c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 271c3e2dc6bSNicolas Souchu int error; 272c3e2dc6bSNicolas Souchu 273c3e2dc6bSNicolas Souchu switch (how) { 274c3e2dc6bSNicolas Souchu case SMB_QWRITE: 27504f89a63SNicolas Souchu error = iicbus_start(parent, slave & ~LSB, 0); 276c3e2dc6bSNicolas Souchu break; 277c3e2dc6bSNicolas Souchu 278c3e2dc6bSNicolas Souchu case SMB_QREAD: 27904f89a63SNicolas Souchu error = iicbus_start(parent, slave | LSB, 0); 280c3e2dc6bSNicolas Souchu break; 281c3e2dc6bSNicolas Souchu 282c3e2dc6bSNicolas Souchu default: 283c3e2dc6bSNicolas Souchu error = EINVAL; 284c3e2dc6bSNicolas Souchu break; 285c3e2dc6bSNicolas Souchu } 286c3e2dc6bSNicolas Souchu 287c3e2dc6bSNicolas Souchu if (!error) 288c3e2dc6bSNicolas Souchu error = iicbus_stop(parent); 289c3e2dc6bSNicolas Souchu 290c3e2dc6bSNicolas Souchu return (error); 291c3e2dc6bSNicolas Souchu } 292c3e2dc6bSNicolas Souchu 293c3e2dc6bSNicolas Souchu static int 294c3e2dc6bSNicolas Souchu iicsmb_sendb(device_t dev, u_char slave, char byte) 295c3e2dc6bSNicolas Souchu { 296c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 297c3e2dc6bSNicolas Souchu int error, sent; 298c3e2dc6bSNicolas Souchu 29904f89a63SNicolas Souchu error = iicbus_start(parent, slave & ~LSB, 0); 300c3e2dc6bSNicolas Souchu 301c3e2dc6bSNicolas Souchu if (!error) { 30204f89a63SNicolas Souchu error = iicbus_write(parent, &byte, 1, &sent, 0); 303c3e2dc6bSNicolas Souchu 304c3e2dc6bSNicolas Souchu iicbus_stop(parent); 305c3e2dc6bSNicolas Souchu } 306c3e2dc6bSNicolas Souchu 307c3e2dc6bSNicolas Souchu return (error); 308c3e2dc6bSNicolas Souchu } 309c3e2dc6bSNicolas Souchu 310c3e2dc6bSNicolas Souchu static int 311c3e2dc6bSNicolas Souchu iicsmb_recvb(device_t dev, u_char slave, char *byte) 312c3e2dc6bSNicolas Souchu { 313c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 314c3e2dc6bSNicolas Souchu int error, read; 315c3e2dc6bSNicolas Souchu 31604f89a63SNicolas Souchu error = iicbus_start(parent, slave | LSB, 0); 317c3e2dc6bSNicolas Souchu 31804f89a63SNicolas Souchu if (!error) { 31904f89a63SNicolas Souchu error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0); 32004f89a63SNicolas Souchu 32104f89a63SNicolas Souchu iicbus_stop(parent); 32204f89a63SNicolas Souchu } 323c3e2dc6bSNicolas Souchu 324c3e2dc6bSNicolas Souchu return (error); 325c3e2dc6bSNicolas Souchu } 326c3e2dc6bSNicolas Souchu 327c3e2dc6bSNicolas Souchu static int 328c3e2dc6bSNicolas Souchu iicsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 329c3e2dc6bSNicolas Souchu { 330c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 331c3e2dc6bSNicolas Souchu int error, sent; 332c3e2dc6bSNicolas Souchu 33304f89a63SNicolas Souchu error = iicbus_start(parent, slave & ~LSB, 0); 334c3e2dc6bSNicolas Souchu 335c3e2dc6bSNicolas Souchu if (!error) { 33604f89a63SNicolas Souchu if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0))) 33704f89a63SNicolas Souchu error = iicbus_write(parent, &byte, 1, &sent, 0); 338c3e2dc6bSNicolas Souchu 339c3e2dc6bSNicolas Souchu iicbus_stop(parent); 340c3e2dc6bSNicolas Souchu } 341c3e2dc6bSNicolas Souchu 342c3e2dc6bSNicolas Souchu return (error); 343c3e2dc6bSNicolas Souchu } 344c3e2dc6bSNicolas Souchu 345c3e2dc6bSNicolas Souchu static int 346c3e2dc6bSNicolas Souchu iicsmb_writew(device_t dev, u_char slave, char cmd, short word) 347c3e2dc6bSNicolas Souchu { 348c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 349c3e2dc6bSNicolas Souchu int error, sent; 350c3e2dc6bSNicolas Souchu 351c3e2dc6bSNicolas Souchu char low = (char)(word & 0xff); 352c3e2dc6bSNicolas Souchu char high = (char)((word & 0xff00) >> 8); 353c3e2dc6bSNicolas Souchu 35404f89a63SNicolas Souchu error = iicbus_start(parent, slave & ~LSB, 0); 355c3e2dc6bSNicolas Souchu 356c3e2dc6bSNicolas Souchu if (!error) { 35704f89a63SNicolas Souchu if (!(error = iicbus_write(parent, &cmd, 1, &sent, 0))) 35804f89a63SNicolas Souchu if (!(error = iicbus_write(parent, &low, 1, &sent, 0))) 35904f89a63SNicolas Souchu error = iicbus_write(parent, &high, 1, &sent, 0); 360c3e2dc6bSNicolas Souchu 361c3e2dc6bSNicolas Souchu iicbus_stop(parent); 362c3e2dc6bSNicolas Souchu } 363c3e2dc6bSNicolas Souchu 364c3e2dc6bSNicolas Souchu return (error); 365c3e2dc6bSNicolas Souchu } 366c3e2dc6bSNicolas Souchu 367c3e2dc6bSNicolas Souchu static int 368c3e2dc6bSNicolas Souchu iicsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 369c3e2dc6bSNicolas Souchu { 370c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 371c3e2dc6bSNicolas Souchu int error, sent, read; 372c3e2dc6bSNicolas Souchu 37304f89a63SNicolas Souchu if ((error = iicbus_start(parent, slave & ~LSB, 0))) 37404f89a63SNicolas Souchu return (error); 37504f89a63SNicolas Souchu 37604f89a63SNicolas Souchu if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 377c3e2dc6bSNicolas Souchu goto error; 378c3e2dc6bSNicolas Souchu 37904f89a63SNicolas Souchu if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 380c3e2dc6bSNicolas Souchu goto error; 381c3e2dc6bSNicolas Souchu 38204f89a63SNicolas Souchu if ((error = iicbus_read(parent, byte, 1, &read, IIC_LAST_READ, 0))) 383c3e2dc6bSNicolas Souchu goto error; 384c3e2dc6bSNicolas Souchu 385c3e2dc6bSNicolas Souchu error: 38604f89a63SNicolas Souchu iicbus_stop(parent); 387c3e2dc6bSNicolas Souchu return (error); 388c3e2dc6bSNicolas Souchu } 389c3e2dc6bSNicolas Souchu 390c3e2dc6bSNicolas Souchu #define BUF2SHORT(low,high) \ 391c3e2dc6bSNicolas Souchu ((short)(((high) & 0xff) << 8) | (short)((low) & 0xff)) 392c3e2dc6bSNicolas Souchu 393c3e2dc6bSNicolas Souchu static int 394c3e2dc6bSNicolas Souchu iicsmb_readw(device_t dev, u_char slave, char cmd, short *word) 395c3e2dc6bSNicolas Souchu { 396c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 397c3e2dc6bSNicolas Souchu int error, sent, read; 398c3e2dc6bSNicolas Souchu char buf[2]; 399c3e2dc6bSNicolas Souchu 40004f89a63SNicolas Souchu if ((error = iicbus_start(parent, slave & ~LSB, 0))) 40104f89a63SNicolas Souchu return (error); 40204f89a63SNicolas Souchu 40304f89a63SNicolas Souchu if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 404c3e2dc6bSNicolas Souchu goto error; 405c3e2dc6bSNicolas Souchu 40604f89a63SNicolas Souchu if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 407c3e2dc6bSNicolas Souchu goto error; 408c3e2dc6bSNicolas Souchu 40904f89a63SNicolas Souchu if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0))) 410c3e2dc6bSNicolas Souchu goto error; 411c3e2dc6bSNicolas Souchu 412c3e2dc6bSNicolas Souchu /* first, receive low, then high byte */ 413c3e2dc6bSNicolas Souchu *word = BUF2SHORT(buf[0], buf[1]); 414c3e2dc6bSNicolas Souchu 415c3e2dc6bSNicolas Souchu error: 41604f89a63SNicolas Souchu iicbus_stop(parent); 417c3e2dc6bSNicolas Souchu return (error); 418c3e2dc6bSNicolas Souchu } 419c3e2dc6bSNicolas Souchu 420c3e2dc6bSNicolas Souchu static int 421c3e2dc6bSNicolas Souchu iicsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 422c3e2dc6bSNicolas Souchu { 423c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 424c3e2dc6bSNicolas Souchu int error, sent, read; 425c3e2dc6bSNicolas Souchu char buf[2]; 426c3e2dc6bSNicolas Souchu 42704f89a63SNicolas Souchu if ((error = iicbus_start(parent, slave & ~LSB, 0))) 42804f89a63SNicolas Souchu return (error); 429c3e2dc6bSNicolas Souchu 43004f89a63SNicolas Souchu if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 431c3e2dc6bSNicolas Souchu goto error; 432c3e2dc6bSNicolas Souchu 433c3e2dc6bSNicolas Souchu /* first, send low, then high byte */ 434c3e2dc6bSNicolas Souchu buf[0] = (char)(sdata & 0xff); 435c3e2dc6bSNicolas Souchu buf[1] = (char)((sdata & 0xff00) >> 8); 436c3e2dc6bSNicolas Souchu 43704f89a63SNicolas Souchu if ((error = iicbus_write(parent, buf, 2, &sent, 0))) 438c3e2dc6bSNicolas Souchu goto error; 439c3e2dc6bSNicolas Souchu 44004f89a63SNicolas Souchu if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 441c3e2dc6bSNicolas Souchu goto error; 442c3e2dc6bSNicolas Souchu 44304f89a63SNicolas Souchu if ((error = iicbus_read(parent, buf, 2, &read, IIC_LAST_READ, 0))) 444c3e2dc6bSNicolas Souchu goto error; 445c3e2dc6bSNicolas Souchu 446c3e2dc6bSNicolas Souchu /* first, receive low, then high byte */ 447c3e2dc6bSNicolas Souchu *rdata = BUF2SHORT(buf[0], buf[1]); 448c3e2dc6bSNicolas Souchu 449c3e2dc6bSNicolas Souchu error: 45004f89a63SNicolas Souchu iicbus_stop(parent); 451c3e2dc6bSNicolas Souchu return (error); 452c3e2dc6bSNicolas Souchu } 453c3e2dc6bSNicolas Souchu 454c3e2dc6bSNicolas Souchu static int 455c3e2dc6bSNicolas Souchu iicsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 456c3e2dc6bSNicolas Souchu { 457c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 458c3e2dc6bSNicolas Souchu int error, sent; 459c3e2dc6bSNicolas Souchu 46004f89a63SNicolas Souchu if ((error = iicbus_start(parent, slave & ~LSB, 0))) 461c3e2dc6bSNicolas Souchu goto error; 462c3e2dc6bSNicolas Souchu 46304f89a63SNicolas Souchu if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 464c3e2dc6bSNicolas Souchu goto error; 465c3e2dc6bSNicolas Souchu 46604f89a63SNicolas Souchu if ((error = iicbus_write(parent, buf, (int)count, &sent, 0))) 467c3e2dc6bSNicolas Souchu goto error; 468c3e2dc6bSNicolas Souchu 469c3e2dc6bSNicolas Souchu if ((error = iicbus_stop(parent))) 470c3e2dc6bSNicolas Souchu goto error; 471c3e2dc6bSNicolas Souchu 472c3e2dc6bSNicolas Souchu error: 473c3e2dc6bSNicolas Souchu return (error); 474c3e2dc6bSNicolas Souchu } 475c3e2dc6bSNicolas Souchu 476c3e2dc6bSNicolas Souchu static int 477c3e2dc6bSNicolas Souchu iicsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 478c3e2dc6bSNicolas Souchu { 479c3e2dc6bSNicolas Souchu device_t parent = device_get_parent(dev); 480c3e2dc6bSNicolas Souchu int error, sent, read; 481c3e2dc6bSNicolas Souchu 48204f89a63SNicolas Souchu if ((error = iicbus_start(parent, slave & ~LSB, 0))) 48304f89a63SNicolas Souchu return (error); 48404f89a63SNicolas Souchu 48504f89a63SNicolas Souchu if ((error = iicbus_write(parent, &cmd, 1, &sent, 0))) 486c3e2dc6bSNicolas Souchu goto error; 487c3e2dc6bSNicolas Souchu 48804f89a63SNicolas Souchu if ((error = iicbus_repeated_start(parent, slave | LSB, 0))) 489c3e2dc6bSNicolas Souchu goto error; 490c3e2dc6bSNicolas Souchu 49104f89a63SNicolas Souchu if ((error = iicbus_read(parent, buf, (int)count, &read, 49204f89a63SNicolas Souchu IIC_LAST_READ, 0))) 493c3e2dc6bSNicolas Souchu goto error; 494c3e2dc6bSNicolas Souchu 495c3e2dc6bSNicolas Souchu error: 49604f89a63SNicolas Souchu iicbus_stop(parent); 497c3e2dc6bSNicolas Souchu return (error); 498c3e2dc6bSNicolas Souchu } 499c3e2dc6bSNicolas Souchu 500c3e2dc6bSNicolas Souchu DRIVER_MODULE(iicsmb, iicbus, iicsmb_driver, iicsmb_devclass, 0, 0); 501