1ca2e4ecdSMichael Gmelin /*- 2ca2e4ecdSMichael Gmelin * Copyright (c) 2015 Michael Gmelin <freebsd@grem.de> 3ca2e4ecdSMichael Gmelin * All rights reserved. 4ca2e4ecdSMichael Gmelin * 5ca2e4ecdSMichael Gmelin * Redistribution and use in source and binary forms, with or without 6ca2e4ecdSMichael Gmelin * modification, are permitted provided that the following conditions 7ca2e4ecdSMichael Gmelin * are met: 8ca2e4ecdSMichael Gmelin * 1. Redistributions of source code must retain the above copyright 9ca2e4ecdSMichael Gmelin * notice, this list of conditions and the following disclaimer. 10ca2e4ecdSMichael Gmelin * 2. Redistributions in binary form must reproduce the above copyright 11ca2e4ecdSMichael Gmelin * notice, this list of conditions and the following disclaimer in the 12ca2e4ecdSMichael Gmelin * documentation and/or other materials provided with the distribution. 13ca2e4ecdSMichael Gmelin * 14ca2e4ecdSMichael Gmelin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15ca2e4ecdSMichael Gmelin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16ca2e4ecdSMichael Gmelin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17ca2e4ecdSMichael Gmelin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18ca2e4ecdSMichael Gmelin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19ca2e4ecdSMichael Gmelin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20ca2e4ecdSMichael Gmelin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21ca2e4ecdSMichael Gmelin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22ca2e4ecdSMichael Gmelin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23ca2e4ecdSMichael Gmelin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24ca2e4ecdSMichael Gmelin * SUCH DAMAGE. 25ca2e4ecdSMichael Gmelin */ 26ca2e4ecdSMichael Gmelin 27ca2e4ecdSMichael Gmelin #include <sys/cdefs.h> 28ca2e4ecdSMichael Gmelin __FBSDID("$FreeBSD$"); 29ca2e4ecdSMichael Gmelin 30ca2e4ecdSMichael Gmelin /* 31ca2e4ecdSMichael Gmelin * Driver for intersil I2C ISL29018 Digital Ambient Light Sensor and Proximity 32ca2e4ecdSMichael Gmelin * Sensor with Interrupt Function, only tested connected over SMBus (ig4iic). 33ca2e4ecdSMichael Gmelin * 34ca2e4ecdSMichael Gmelin * Datasheet: 35ca2e4ecdSMichael Gmelin * http://www.intersil.com/en/products/optoelectronics/ambient-light-and-proximity-sensors/light-to-digital-sensors/ISL29018.html 36ca2e4ecdSMichael Gmelin * http://www.intersil.com/content/dam/Intersil/documents/isl2/isl29018.pdf 37ca2e4ecdSMichael Gmelin */ 38ca2e4ecdSMichael Gmelin 39ca2e4ecdSMichael Gmelin #include <sys/param.h> 40ca2e4ecdSMichael Gmelin #include <sys/bus.h> 41ca2e4ecdSMichael Gmelin #include <sys/conf.h> 42ca2e4ecdSMichael Gmelin #include <sys/event.h> 43ca2e4ecdSMichael Gmelin #include <sys/fcntl.h> 44ca2e4ecdSMichael Gmelin #include <sys/kernel.h> 45ca2e4ecdSMichael Gmelin #include <sys/lock.h> 46ca2e4ecdSMichael Gmelin #include <sys/lockmgr.h> 47ca2e4ecdSMichael Gmelin #include <sys/malloc.h> 48ca2e4ecdSMichael Gmelin #include <sys/mbuf.h> 49ca2e4ecdSMichael Gmelin #include <sys/module.h> 50ca2e4ecdSMichael Gmelin #include <sys/poll.h> 51ca2e4ecdSMichael Gmelin #include <sys/sx.h> 52ca2e4ecdSMichael Gmelin #include <sys/sysctl.h> 53ca2e4ecdSMichael Gmelin #include <sys/systm.h> 54ca2e4ecdSMichael Gmelin #include <sys/systm.h> 55ca2e4ecdSMichael Gmelin #include <sys/uio.h> 56ca2e4ecdSMichael Gmelin #include <sys/vnode.h> 57ca2e4ecdSMichael Gmelin 58ca2e4ecdSMichael Gmelin #include <dev/smbus/smbconf.h> 59ca2e4ecdSMichael Gmelin #include <dev/smbus/smbus.h> 60ca2e4ecdSMichael Gmelin #include <dev/isl/isl.h> 61ca2e4ecdSMichael Gmelin 62ca2e4ecdSMichael Gmelin #include "smbus_if.h" 63ca2e4ecdSMichael Gmelin #include "bus_if.h" 64ca2e4ecdSMichael Gmelin #include "device_if.h" 65ca2e4ecdSMichael Gmelin 66ca2e4ecdSMichael Gmelin #define ISL_METHOD_ALS 0x10 67ca2e4ecdSMichael Gmelin #define ISL_METHOD_IR 0x11 68ca2e4ecdSMichael Gmelin #define ISL_METHOD_PROX 0x12 69ca2e4ecdSMichael Gmelin #define ISL_METHOD_RESOLUTION 0x13 70ca2e4ecdSMichael Gmelin #define ISL_METHOD_RANGE 0x14 71ca2e4ecdSMichael Gmelin 72ca2e4ecdSMichael Gmelin struct isl_softc { 73ca2e4ecdSMichael Gmelin device_t dev; 74ca2e4ecdSMichael Gmelin int addr; 75ca2e4ecdSMichael Gmelin 76ca2e4ecdSMichael Gmelin struct sx isl_sx; 77ca2e4ecdSMichael Gmelin }; 78ca2e4ecdSMichael Gmelin 79ca2e4ecdSMichael Gmelin /* Returns < 0 on problem. */ 80ca2e4ecdSMichael Gmelin static int isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask); 81ca2e4ecdSMichael Gmelin 82ca2e4ecdSMichael Gmelin /* 83ca2e4ecdSMichael Gmelin * Initialize the device 84ca2e4ecdSMichael Gmelin */ 85*12e413beSMichael Gmelin static int 86ca2e4ecdSMichael Gmelin init_device(device_t dev, int addr, int probe) 87ca2e4ecdSMichael Gmelin { 88ca2e4ecdSMichael Gmelin static char bl_init[] = { 0x00 }; 89ca2e4ecdSMichael Gmelin 90ca2e4ecdSMichael Gmelin device_t bus; 91ca2e4ecdSMichael Gmelin int error; 92ca2e4ecdSMichael Gmelin 93ca2e4ecdSMichael Gmelin bus = device_get_parent(dev); /* smbus */ 94ca2e4ecdSMichael Gmelin 95ca2e4ecdSMichael Gmelin /* 96ca2e4ecdSMichael Gmelin * init procedure: send 0x00 to test ref and cmd reg 1 97ca2e4ecdSMichael Gmelin */ 98ca2e4ecdSMichael Gmelin error = smbus_trans(bus, addr, REG_TEST, 99ca2e4ecdSMichael Gmelin SMB_TRANS_NOCNT | SMB_TRANS_7BIT, 100ca2e4ecdSMichael Gmelin bl_init, sizeof(bl_init), NULL, 0, NULL); 101ca2e4ecdSMichael Gmelin if (error) 102ca2e4ecdSMichael Gmelin goto done; 103ca2e4ecdSMichael Gmelin 104ca2e4ecdSMichael Gmelin error = smbus_trans(bus, addr, REG_CMD1, 105ca2e4ecdSMichael Gmelin SMB_TRANS_NOCNT | SMB_TRANS_7BIT, 106ca2e4ecdSMichael Gmelin bl_init, sizeof(bl_init), NULL, 0, NULL); 107ca2e4ecdSMichael Gmelin if (error) 108ca2e4ecdSMichael Gmelin goto done; 109ca2e4ecdSMichael Gmelin 110ca2e4ecdSMichael Gmelin pause("islinit", hz/100); 111ca2e4ecdSMichael Gmelin 112ca2e4ecdSMichael Gmelin done: 113ca2e4ecdSMichael Gmelin if (error) 114ca2e4ecdSMichael Gmelin device_printf(dev, "Unable to initialize\n"); 115ca2e4ecdSMichael Gmelin return (error); 116ca2e4ecdSMichael Gmelin } 117ca2e4ecdSMichael Gmelin 118ca2e4ecdSMichael Gmelin static int isl_probe(device_t); 119ca2e4ecdSMichael Gmelin static int isl_attach(device_t); 120ca2e4ecdSMichael Gmelin static int isl_detach(device_t); 121ca2e4ecdSMichael Gmelin 122ca2e4ecdSMichael Gmelin static int isl_sysctl(SYSCTL_HANDLER_ARGS); 123ca2e4ecdSMichael Gmelin 124ca2e4ecdSMichael Gmelin static devclass_t isl_devclass; 125ca2e4ecdSMichael Gmelin 126ca2e4ecdSMichael Gmelin static device_method_t isl_methods[] = { 127ca2e4ecdSMichael Gmelin /* device interface */ 128ca2e4ecdSMichael Gmelin DEVMETHOD(device_probe, isl_probe), 129ca2e4ecdSMichael Gmelin DEVMETHOD(device_attach, isl_attach), 130ca2e4ecdSMichael Gmelin DEVMETHOD(device_detach, isl_detach), 131ca2e4ecdSMichael Gmelin 132ca2e4ecdSMichael Gmelin DEVMETHOD_END 133ca2e4ecdSMichael Gmelin }; 134ca2e4ecdSMichael Gmelin 135ca2e4ecdSMichael Gmelin static driver_t isl_driver = { 136ca2e4ecdSMichael Gmelin "isl", 137ca2e4ecdSMichael Gmelin isl_methods, 138ca2e4ecdSMichael Gmelin sizeof(struct isl_softc), 139ca2e4ecdSMichael Gmelin }; 140ca2e4ecdSMichael Gmelin 141ca2e4ecdSMichael Gmelin static int 142ca2e4ecdSMichael Gmelin isl_probe(device_t dev) 143ca2e4ecdSMichael Gmelin { 144ca2e4ecdSMichael Gmelin int addr; 145ca2e4ecdSMichael Gmelin int error; 146ca2e4ecdSMichael Gmelin 147ca2e4ecdSMichael Gmelin addr = smbus_get_addr(dev); 148ca2e4ecdSMichael Gmelin 149ca2e4ecdSMichael Gmelin /* 150ca2e4ecdSMichael Gmelin * 0x44 - isl ambient light sensor on the acer c720. 151ca2e4ecdSMichael Gmelin * (other devices might use other ids). 152ca2e4ecdSMichael Gmelin */ 153ca2e4ecdSMichael Gmelin if (addr != 0x44) 154ca2e4ecdSMichael Gmelin return (ENXIO); 155ca2e4ecdSMichael Gmelin 156ca2e4ecdSMichael Gmelin error = init_device(dev, addr, 1); 157ca2e4ecdSMichael Gmelin if (error) 158ca2e4ecdSMichael Gmelin return (ENXIO); 159ca2e4ecdSMichael Gmelin 160ca2e4ecdSMichael Gmelin device_set_desc(dev, "ISL Digital Ambient Light Sensor"); 161ca2e4ecdSMichael Gmelin 162ca2e4ecdSMichael Gmelin return (BUS_PROBE_VENDOR); 163ca2e4ecdSMichael Gmelin } 164ca2e4ecdSMichael Gmelin 165ca2e4ecdSMichael Gmelin static int 166ca2e4ecdSMichael Gmelin isl_attach(device_t dev) 167ca2e4ecdSMichael Gmelin { 168ca2e4ecdSMichael Gmelin struct isl_softc *sc; 169*12e413beSMichael Gmelin struct sysctl_ctx_list *sysctl_ctx; 170*12e413beSMichael Gmelin struct sysctl_oid *sysctl_tree; 171ca2e4ecdSMichael Gmelin int addr; 172ca2e4ecdSMichael Gmelin int use_als; 173ca2e4ecdSMichael Gmelin int use_ir; 174ca2e4ecdSMichael Gmelin int use_prox; 175ca2e4ecdSMichael Gmelin 176ca2e4ecdSMichael Gmelin sc = device_get_softc(dev); 177ca2e4ecdSMichael Gmelin 178ca2e4ecdSMichael Gmelin if (!sc) 179ca2e4ecdSMichael Gmelin return (ENOMEM); 180ca2e4ecdSMichael Gmelin 181*12e413beSMichael Gmelin addr = smbus_get_addr(dev); 182ca2e4ecdSMichael Gmelin 183ca2e4ecdSMichael Gmelin if (init_device(dev, addr, 0)) 184ca2e4ecdSMichael Gmelin return (ENXIO); 185ca2e4ecdSMichael Gmelin 186ca2e4ecdSMichael Gmelin sx_init(&sc->isl_sx, "ISL read lock"); 187ca2e4ecdSMichael Gmelin 188ca2e4ecdSMichael Gmelin sc->dev = dev; 189ca2e4ecdSMichael Gmelin sc->addr = addr; 190ca2e4ecdSMichael Gmelin 191*12e413beSMichael Gmelin sysctl_ctx = device_get_sysctl_ctx(dev); 192*12e413beSMichael Gmelin sysctl_tree = device_get_sysctl_tree(dev); 193ca2e4ecdSMichael Gmelin 194ca2e4ecdSMichael Gmelin use_als = isl_read_sensor(dev, addr, CMD1_MASK_ALS_ONCE) >= 0; 195ca2e4ecdSMichael Gmelin use_ir = isl_read_sensor(dev, addr, CMD1_MASK_IR_ONCE) >= 0; 196ca2e4ecdSMichael Gmelin use_prox = isl_read_sensor(dev, addr, CMD1_MASK_PROX_ONCE) >= 0; 197ca2e4ecdSMichael Gmelin 198ca2e4ecdSMichael Gmelin if (use_als) { 199*12e413beSMichael Gmelin SYSCTL_ADD_PROC(sysctl_ctx, 200*12e413beSMichael Gmelin SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, 201ca2e4ecdSMichael Gmelin "als", CTLTYPE_INT | CTLFLAG_RD, 202ca2e4ecdSMichael Gmelin sc, ISL_METHOD_ALS, isl_sysctl, "I", 203ca2e4ecdSMichael Gmelin "Current ALS sensor read-out"); 204ca2e4ecdSMichael Gmelin } 205ca2e4ecdSMichael Gmelin 206ca2e4ecdSMichael Gmelin if (use_ir) { 207*12e413beSMichael Gmelin SYSCTL_ADD_PROC(sysctl_ctx, 208*12e413beSMichael Gmelin SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, 209ca2e4ecdSMichael Gmelin "ir", CTLTYPE_INT | CTLFLAG_RD, 210ca2e4ecdSMichael Gmelin sc, ISL_METHOD_IR, isl_sysctl, "I", 211ca2e4ecdSMichael Gmelin "Current IR sensor read-out"); 212ca2e4ecdSMichael Gmelin } 213ca2e4ecdSMichael Gmelin 214ca2e4ecdSMichael Gmelin if (use_prox) { 215*12e413beSMichael Gmelin SYSCTL_ADD_PROC(sysctl_ctx, 216*12e413beSMichael Gmelin SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, 217ca2e4ecdSMichael Gmelin "prox", CTLTYPE_INT | CTLFLAG_RD, 218ca2e4ecdSMichael Gmelin sc, ISL_METHOD_PROX, isl_sysctl, "I", 219ca2e4ecdSMichael Gmelin "Current proximity sensor read-out"); 220ca2e4ecdSMichael Gmelin } 221ca2e4ecdSMichael Gmelin 222*12e413beSMichael Gmelin SYSCTL_ADD_PROC(sysctl_ctx, 223*12e413beSMichael Gmelin SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, 224ca2e4ecdSMichael Gmelin "resolution", CTLTYPE_INT | CTLFLAG_RD, 225ca2e4ecdSMichael Gmelin sc, ISL_METHOD_RESOLUTION, isl_sysctl, "I", 226ca2e4ecdSMichael Gmelin "Current proximity sensor resolution"); 227ca2e4ecdSMichael Gmelin 228*12e413beSMichael Gmelin SYSCTL_ADD_PROC(sysctl_ctx, 229*12e413beSMichael Gmelin SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, 230ca2e4ecdSMichael Gmelin "range", CTLTYPE_INT | CTLFLAG_RD, 231ca2e4ecdSMichael Gmelin sc, ISL_METHOD_RANGE, isl_sysctl, "I", 232ca2e4ecdSMichael Gmelin "Current proximity sensor range"); 233ca2e4ecdSMichael Gmelin 234ca2e4ecdSMichael Gmelin return (0); 235ca2e4ecdSMichael Gmelin } 236ca2e4ecdSMichael Gmelin 237ca2e4ecdSMichael Gmelin static int 238ca2e4ecdSMichael Gmelin isl_detach(device_t dev) 239ca2e4ecdSMichael Gmelin { 240ca2e4ecdSMichael Gmelin struct isl_softc *sc; 241ca2e4ecdSMichael Gmelin 242ca2e4ecdSMichael Gmelin sc = device_get_softc(dev); 243ca2e4ecdSMichael Gmelin sx_destroy(&sc->isl_sx); 244ca2e4ecdSMichael Gmelin 245ca2e4ecdSMichael Gmelin return (0); 246ca2e4ecdSMichael Gmelin } 247ca2e4ecdSMichael Gmelin 248ca2e4ecdSMichael Gmelin static int 249ca2e4ecdSMichael Gmelin isl_sysctl(SYSCTL_HANDLER_ARGS) 250ca2e4ecdSMichael Gmelin { 251ca2e4ecdSMichael Gmelin static int resolutions[] = { 16, 12, 8, 4}; 252ca2e4ecdSMichael Gmelin static int ranges[] = { 1000, 4000, 16000, 64000}; 253ca2e4ecdSMichael Gmelin 254ca2e4ecdSMichael Gmelin struct isl_softc *sc; 255ca2e4ecdSMichael Gmelin device_t bus; 256ca2e4ecdSMichael Gmelin uint8_t rbyte; 257ca2e4ecdSMichael Gmelin int arg; 258ca2e4ecdSMichael Gmelin int resolution; 259ca2e4ecdSMichael Gmelin int range; 260ca2e4ecdSMichael Gmelin 261ca2e4ecdSMichael Gmelin sc = (struct isl_softc *)oidp->oid_arg1; 262ca2e4ecdSMichael Gmelin arg = -1; 263ca2e4ecdSMichael Gmelin 264ca2e4ecdSMichael Gmelin sx_xlock(&sc->isl_sx); 265ca2e4ecdSMichael Gmelin bus = device_get_parent(sc->dev); /* smbus */ 266ca2e4ecdSMichael Gmelin if (smbus_trans(bus, sc->addr, REG_CMD2, 267ca2e4ecdSMichael Gmelin SMB_TRANS_NOCNT | SMB_TRANS_7BIT, 268ca2e4ecdSMichael Gmelin NULL, 0, &rbyte, sizeof(rbyte), NULL)) { 269ca2e4ecdSMichael Gmelin sx_xunlock(&sc->isl_sx); 270ca2e4ecdSMichael Gmelin return (-1); 271ca2e4ecdSMichael Gmelin } 272ca2e4ecdSMichael Gmelin resolution = resolutions[(rbyte & CMD2_MASK_RESOLUTION) 273ca2e4ecdSMichael Gmelin >> CMD2_SHIFT_RESOLUTION]; 274ca2e4ecdSMichael Gmelin range = ranges[(rbyte & CMD2_MASK_RANGE) >> CMD2_SHIFT_RANGE]; 275ca2e4ecdSMichael Gmelin 276ca2e4ecdSMichael Gmelin switch (oidp->oid_arg2) { 277ca2e4ecdSMichael Gmelin case ISL_METHOD_ALS: 278ca2e4ecdSMichael Gmelin arg = (isl_read_sensor(sc->dev, sc->addr, 279ca2e4ecdSMichael Gmelin CMD1_MASK_ALS_ONCE) * range) >> resolution; 280ca2e4ecdSMichael Gmelin break; 281ca2e4ecdSMichael Gmelin case ISL_METHOD_IR: 282ca2e4ecdSMichael Gmelin arg = isl_read_sensor(sc->dev, sc->addr, 283ca2e4ecdSMichael Gmelin CMD1_MASK_IR_ONCE); 284ca2e4ecdSMichael Gmelin break; 285ca2e4ecdSMichael Gmelin case ISL_METHOD_PROX: 286ca2e4ecdSMichael Gmelin arg = isl_read_sensor(sc->dev, sc->addr, 287ca2e4ecdSMichael Gmelin CMD1_MASK_PROX_ONCE); 288ca2e4ecdSMichael Gmelin break; 289ca2e4ecdSMichael Gmelin case ISL_METHOD_RESOLUTION: 290ca2e4ecdSMichael Gmelin arg = (1 << resolution); 291ca2e4ecdSMichael Gmelin break; 292ca2e4ecdSMichael Gmelin case ISL_METHOD_RANGE: 293ca2e4ecdSMichael Gmelin arg = range; 294ca2e4ecdSMichael Gmelin break; 295ca2e4ecdSMichael Gmelin } 296ca2e4ecdSMichael Gmelin sx_xunlock(&sc->isl_sx); 297ca2e4ecdSMichael Gmelin 298ca2e4ecdSMichael Gmelin SYSCTL_OUT(req, &arg, sizeof(arg)); 299ca2e4ecdSMichael Gmelin return (0); 300ca2e4ecdSMichael Gmelin } 301ca2e4ecdSMichael Gmelin 302*12e413beSMichael Gmelin static int 303*12e413beSMichael Gmelin isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask) 304ca2e4ecdSMichael Gmelin { 305ca2e4ecdSMichael Gmelin device_t bus; 306ca2e4ecdSMichael Gmelin uint8_t rbyte; 307ca2e4ecdSMichael Gmelin uint8_t cmd; 308ca2e4ecdSMichael Gmelin int ret; 309ca2e4ecdSMichael Gmelin 310ca2e4ecdSMichael Gmelin bus = device_get_parent(dev); /* smbus */ 311ca2e4ecdSMichael Gmelin 312ca2e4ecdSMichael Gmelin if (smbus_trans(bus, addr, REG_CMD1, 313ca2e4ecdSMichael Gmelin SMB_TRANS_NOCNT | SMB_TRANS_7BIT, 314ca2e4ecdSMichael Gmelin NULL, 0, &rbyte, sizeof(rbyte), NULL)) { 315ca2e4ecdSMichael Gmelin device_printf(dev, 316ca2e4ecdSMichael Gmelin "Couldn't read first byte before issuing command %d\n", 317ca2e4ecdSMichael Gmelin cmd_mask); 318ca2e4ecdSMichael Gmelin return (-1); 319ca2e4ecdSMichael Gmelin } 320ca2e4ecdSMichael Gmelin 321ca2e4ecdSMichael Gmelin cmd = (rbyte & 0x1f) | cmd_mask; 322ca2e4ecdSMichael Gmelin if (smbus_trans(bus, addr, REG_CMD1, 323ca2e4ecdSMichael Gmelin SMB_TRANS_NOCNT | SMB_TRANS_7BIT, 324ca2e4ecdSMichael Gmelin &cmd, sizeof(cmd), NULL, 0, NULL)) { 325ca2e4ecdSMichael Gmelin device_printf(dev, "Couldn't write command %d\n", cmd_mask); 326ca2e4ecdSMichael Gmelin return (-1); 327ca2e4ecdSMichael Gmelin } 328ca2e4ecdSMichael Gmelin 329ca2e4ecdSMichael Gmelin pause("islconv", hz/10); 330ca2e4ecdSMichael Gmelin 331ca2e4ecdSMichael Gmelin if (smbus_trans(bus, addr, REG_DATA1, 332ca2e4ecdSMichael Gmelin SMB_TRANS_NOCNT | SMB_TRANS_7BIT, 333ca2e4ecdSMichael Gmelin NULL, 0, &rbyte, sizeof(rbyte), NULL)) { 334ca2e4ecdSMichael Gmelin device_printf(dev, 335ca2e4ecdSMichael Gmelin "Couldn't read first byte after command %d\n", cmd_mask); 336ca2e4ecdSMichael Gmelin return (-1); 337ca2e4ecdSMichael Gmelin } 338ca2e4ecdSMichael Gmelin 339ca2e4ecdSMichael Gmelin ret = rbyte; 340ca2e4ecdSMichael Gmelin if (smbus_trans(bus, addr, REG_DATA2, 341ca2e4ecdSMichael Gmelin SMB_TRANS_NOCNT | SMB_TRANS_7BIT, 342ca2e4ecdSMichael Gmelin NULL, 0, &rbyte, sizeof(rbyte), NULL)) { 343ca2e4ecdSMichael Gmelin device_printf(dev, "Couldn't read second byte after command %d\n", cmd_mask); 344ca2e4ecdSMichael Gmelin return (-1); 345ca2e4ecdSMichael Gmelin } 346ca2e4ecdSMichael Gmelin ret += rbyte << 8; 347ca2e4ecdSMichael Gmelin 348ca2e4ecdSMichael Gmelin return (ret); 349ca2e4ecdSMichael Gmelin } 350ca2e4ecdSMichael Gmelin 351ca2e4ecdSMichael Gmelin DRIVER_MODULE(isl, smbus, isl_driver, isl_devclass, NULL, NULL); 352ca2e4ecdSMichael Gmelin MODULE_DEPEND(isl, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 353ca2e4ecdSMichael Gmelin MODULE_VERSION(isl, 1); 354