Index: head/UPDATING =================================================================== --- head/UPDATING +++ head/UPDATING @@ -51,6 +51,12 @@ ****************************** SPECIAL WARNING: ****************************** +20161030: + isl(4) and cyapa(4) drivers now require a new driver, + chromebook_platform(4), to work properly on Chromebook-class hardware. + On other types of hardware the drivers may need to be configured using + device hints. Please see the corresponding manual pages for details. + 20161017: The urtwn(4) driver was merged into rtwn(4) and now consists of rtwn(4) main module + rtwn_usb(4) and rtwn_pci(4) bus-specific Index: head/share/man/man4/chromebook_platform.4 =================================================================== --- head/share/man/man4/chromebook_platform.4 +++ head/share/man/man4/chromebook_platform.4 @@ -0,0 +1,68 @@ +.\" Copyright (c) 2016 Andriy Gapon +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 13, 2016 +.Dt CHROMEBOOK_PLATFORM 4 +.Os +.Sh NAME +.Nm chromebook_platform +.Nd support driver for hardware on various Chromebook models +.Sh SYNOPSIS +To compile this driver into the kernel, place the following lines into +the kernel configuration file: +.Bd -ragged -offset indent +.Cd "device chromebook_platform" +.Ed +.Pp +Alternatively, to load the driver as a module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +chromebook_platform_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides automatic configuration for devices that cannot be enumerated +or safely probed. +In particular, I2C peripherals are different from model to model. +.Nm +has a model-specific information about the I2C peripherals, their drivers, +their bus attachments and slave addresses. +.Pp +Note that +.Nm +does not load driver modules for the peripherals. +Those have to be compiled into the kernel or loaded separately. +.Sh SEE ALSO +.Xr cyapa 4 , +.Xr iicbus 4 , +.Xr isl 4 , +.Sh AUTHORS +.An -nosplit +The +.Nm +driver and this manual page were written by +.An Andriy Gapon Aq Mt avg@FreeBSD.org . Index: head/share/man/man4/cyapa.4 =================================================================== --- head/share/man/man4/cyapa.4 +++ head/share/man/man4/cyapa.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 25, 2015 +.Dd October 03, 2016 .Dt CYAPA 4 .Os .Sh NAME @@ -36,7 +36,7 @@ .Bd -ragged -offset indent .Cd "device cyapa" .Cd "device ig4" -.Cd "device smbus" +.Cd "device iicbus" .Ed .Pp Alternatively, to load the driver as a module at boot time, place the following line in @@ -45,6 +45,13 @@ cyapa_load="YES" ig4_load="YES" .Ed +.Pp +In +.Pa /boot/device.hints : +.Cd hint.cyapa.0.at="iicbus0" +.Cd hint.cyapa.0.addr="0xCE" +.Cd hint.cyapa.1.at="iicbus1" +.Cd hint.cyapa.1.addr="0xCE" .Sh DESCRIPTION The .Nm @@ -86,6 +93,20 @@ The lower right corner issues a RIGHT button. Optionally, tap to click can be enabled (see below). .El +.Pp +On a system using +.Xr device.hints 5 , +these values are configurable for +.Nm : +.Bl -tag -width "hint.cyapa.%d.addr" +.It Va hint.cyapa.%d.at +target +.Xr iicbus 4 . +.It Va hint.cyapa.%d.addr +.Nm +i2c address on the +.Xr iicbus 4 . +.El .Sh SYSCTL VARIABLES These .Xr sysctl 8 @@ -175,7 +196,7 @@ .Dl debug.cyapa_enable_tapclick=2 .Sh SEE ALSO .Xr ig4 4 , -.Xr smbus 4 , +.Xr iicbus 4 , .Xr sysmouse 4 , .Xr moused 8 .Sh AUTHORS @@ -195,6 +216,6 @@ .Sh BUGS The .Nm -driver detects the device based on its I2C address (0x67). +driver detects the device from the I2C address. This might have unforeseen consequences if the initialization sequence is sent to an unknown device at that address. Index: head/share/man/man4/ig4.4 =================================================================== --- head/share/man/man4/ig4.4 +++ head/share/man/man4/ig4.4 @@ -24,18 +24,18 @@ .\" .\" $FreeBSD$ .\" -.Dd May 30, 2015 +.Dd October 03, 2016 .Dt IG4 4 .Os .Sh NAME .Nm ig4 -.Nd Intel(R) fourth generation mobile CPU integrated I2C SMBus driver +.Nd Intel(R) fourth generation mobile CPU integrated I2C driver .Sh SYNOPSIS To compile this driver into the kernel, place the following lines into the kernel configuration file: .Bd -ragged -offset indent .Cd "device ig4" -.Cd "device smbus" +.Cd "device iicbus" .Ed .Pp Alternatively, to load the driver as a module at boot time, place the following line in @@ -46,9 +46,10 @@ .Sh DESCRIPTION The .Nm -driver provides access to peripherals attached to an I2C SMB controller. +driver provides access to peripherals attached to an I2C controller. +.Sh HARDWARE .Nm -supports the SMBus controller found in fourth generation Intel(R) Core(TM) +supports the I2C controllers found in fourth generation Intel(R) Core(TM) processors based on the mobile U-processor line for intelligent systems. This includes the i7-4650U, i5-4300U, i3-4010U, and 2980U. .Sh SYSCTL VARIABLES @@ -57,13 +58,15 @@ variables are available: .Bl -tag -width "debug.ig4_dump" .It Va debug.ig4_dump -Setting this to a non-zero value dumps controller registers to console and -syslog once. -The sysctl resets to zero immediately. +This sysctl is a zero-based bit mask. +When any of the bits are set, a register dump is printed for +every I2C transfer on an +.Nm +device with the same unit number. .El .Sh SEE ALSO -.Xr smb 4 , -.Xr smbus 4 +.Xr iic 4 , +.Xr iicbus 4 .Sh AUTHORS .An -nosplit The Index: head/share/man/man4/isl.4 =================================================================== --- head/share/man/man4/isl.4 +++ head/share/man/man4/isl.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 25, 2015 +.Dd October 03, 2016 .Dt ISL 4 .Os .Sh NAME @@ -36,7 +36,7 @@ .Bd -ragged -offset indent .Cd "device isl" .Cd "device ig4" -.Cd "device smbus" +.Cd "device iicbus" .Ed .Pp Alternatively, to load the driver as a module at boot time, place the following line in @@ -45,6 +45,13 @@ isl_load="YES" ig4_load="YES" .Ed +.Pp +In +.Pa /boot/device.hints : +.Cd hint.isl.0.at="iicbus0" +.Cd hint.isl.0.addr="0x88" +.Cd hint.isl.1.at="iicbus1" +.Cd hint.isl.1.addr="0x88" .Sh DESCRIPTION The .Nm @@ -54,6 +61,20 @@ Functionality is basic and provided through the .Xr sysctl 8 interface. +.Pp +On a system using +.Xr device.hints 5 , +these values are configurable for +.Nm : +.Bl -tag -width "hint.isl.%d.addr" +.It Va hint.isl.%d.at +target +.Xr iicbus 4 . +.It Va hint.isl.%d.addr +.Nm +i2c address on the +.Xr iicbus 4 . +.El .Sh SYSCTL VARIABLES The following .Xr sysctl 8 @@ -86,7 +107,7 @@ .Ed .Sh SEE ALSO .Xr ig4 4 , -.Xr smbus 4 +.Xr iicbus 4 .Sh AUTHORS .An -nosplit The @@ -99,6 +120,6 @@ .Sh BUGS The .Nm -driver detects the device based on its I2C address (0x44). +driver detects the device based from the I2C address. This might have unforeseen consequences if the initialization sequence is sent to an unknown device at that address. Index: head/sys/conf/files =================================================================== --- head/sys/conf/files +++ head/sys/conf/files @@ -1273,6 +1273,7 @@ dev/cfi/cfi_core.c optional cfi dev/cfi/cfi_dev.c optional cfi dev/cfi/cfi_disk.c optional cfid +dev/chromebook_platform/chromebook_platform.c optional chromebook_platform dev/ciss/ciss.c optional ciss dev/cm/smc90cx6.c optional cm dev/cmx/cmx.c optional cmx @@ -1389,7 +1390,7 @@ dev/cy/cy.c optional cy dev/cy/cy_isa.c optional cy isa dev/cy/cy_pci.c optional cy pci -dev/cyapa/cyapa.c optional cyapa smbus +dev/cyapa/cyapa.c optional cyapa iicbus dev/dc/if_dc.c optional dc pci dev/dc/dcphy.c optional dc pci dev/dc/pnphy.c optional dc pci @@ -1631,8 +1632,8 @@ dev/hwpmc/hwpmc_logging.c optional hwpmc dev/hwpmc/hwpmc_mod.c optional hwpmc dev/hwpmc/hwpmc_soft.c optional hwpmc -dev/ichiic/ig4_iic.c optional ig4 smbus -dev/ichiic/ig4_pci.c optional ig4 pci smbus +dev/ichiic/ig4_iic.c optional ig4 iicbus +dev/ichiic/ig4_pci.c optional ig4 pci iicbus dev/ichsmb/ichsmb.c optional ichsmb dev/ichsmb/ichsmb_pci.c optional ichsmb pci dev/ida/ida.c optional ida @@ -1726,7 +1727,7 @@ dev/iscsi_initiator/isc_sm.c optional iscsi_initiator scbus dev/iscsi_initiator/isc_subr.c optional iscsi_initiator scbus dev/ismt/ismt.c optional ismt -dev/isl/isl.c optional isl smbus +dev/isl/isl.c optional isl iicbus dev/isp/isp.c optional isp dev/isp/isp_freebsd.c optional isp dev/isp/isp_library.c optional isp Index: head/sys/dev/chromebook_platform/chromebook_platform.c =================================================================== --- head/sys/dev/chromebook_platform/chromebook_platform.c +++ head/sys/dev/chromebook_platform/chromebook_platform.c @@ -0,0 +1,102 @@ +/*- + * Copyright (c) 2016 The FreeBSD Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Driver that attaches I2C devices. + */ +static struct { + uint32_t pci_id; + const char *name; + uint8_t addr; +} slaves[] = { + { 0x9c628086, "isl", 0x88 }, + { 0x9c618086, "cyapa", 0xce }, +}; + +static void +chromebook_i2c_identify(driver_t *driver, device_t bus) +{ + device_t controller; + device_t child; + int i; + + /* + * A stopgap approach to preserve the status quo. + * A more intelligent approach is required to correctly + * identify a machine model and hardware available on it. + * For instance, DMI could be used. + * See http://lxr.free-electrons.com/source/drivers/platform/chrome/chromeos_laptop.c + */ + controller = device_get_parent(bus); + if (strcmp(device_get_name(controller), "ig4iic") != 0) + return; + + for (i = 0; i < nitems(slaves); i++) { + if (device_find_child(bus, slaves[i].name, -1) != NULL) + continue; + if (slaves[i].pci_id != pci_get_devid(controller)) + continue; + child = BUS_ADD_CHILD(bus, 0, slaves[i].name, -1); + if (child != NULL) + iicbus_set_addr(child, slaves[i].addr); + } +} + +static device_method_t chromebook_i2c_methods[] = { + DEVMETHOD(device_identify, chromebook_i2c_identify), + { 0, 0 } +}; + +static driver_t chromebook_i2c_driver = { + "chromebook_i2c", + chromebook_i2c_methods, + 0 /* no softc */ +}; + +static devclass_t chromebook_i2c_devclass; + +DRIVER_MODULE(chromebook_i2c, iicbus, chromebook_i2c_driver, + chromebook_i2c_devclass, 0, 0); +MODULE_VERSION(chromebook_i2c, 1); + Index: head/sys/dev/cyapa/cyapa.c =================================================================== --- head/sys/dev/cyapa/cyapa.c +++ head/sys/dev/cyapa/cyapa.c @@ -122,11 +122,11 @@ #include #include -#include -#include +#include +#include #include -#include "smbus_if.h" +#include "iicbus_if.h" #include "bus_if.h" #include "device_if.h" @@ -149,7 +149,6 @@ struct cyapa_softc { device_t dev; int count; /* >0 if device opened */ - int addr; struct cdev *devnode; struct selinfo selinfo; struct mtx mutex; @@ -273,6 +272,30 @@ SYSCTL_INT(_debug, OID_AUTO, cyapa_reset, CTLFLAG_RW, &cyapa_reset, 0, "Reset track pad"); +static int +cyapa_read_bytes(device_t dev, uint8_t reg, uint8_t *val, int cnt) +{ + uint16_t addr = iicbus_get_addr(dev); + struct iic_msg msgs[] = { + { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, + { addr, IIC_M_RD, cnt, val }, + }; + + return (iicbus_transfer(dev, msgs, nitems(msgs))); +} + +static int +cyapa_write_bytes(device_t dev, uint8_t reg, const uint8_t *val, int cnt) +{ + uint16_t addr = iicbus_get_addr(dev); + struct iic_msg msgs[] = { + { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, + { addr, IIC_M_WR | IIC_M_NOSTART, cnt, __DECONST(uint8_t *, val) }, + }; + + return (iicbus_transfer(dev, msgs, nitems(msgs))); +} + static void cyapa_lock(struct cyapa_softc *sc) { @@ -318,7 +341,7 @@ * Initialize the device */ static int -init_device(device_t dev, struct cyapa_cap *cap, int addr, int probe) +init_device(device_t dev, struct cyapa_cap *cap, int probe) { static char bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, @@ -326,17 +349,13 @@ static char bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }; - device_t bus; struct cyapa_boot_regs boot; int error; int retries; - bus = device_get_parent(dev); /* smbus */ - /* Get status */ - error = smbus_trans(bus, addr, CMD_BOOT_STATUS, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, (void *)&boot, sizeof(boot), NULL); + error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, + (void *)&boot, sizeof(boot)); if (error) goto done; @@ -350,25 +369,21 @@ /* Busy, wait loop. */ } else if (boot.error & CYAPA_ERROR_BOOTLOADER) { /* Magic */ - error = smbus_trans(bus, addr, CMD_BOOT_STATUS, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - bl_deactivate, sizeof(bl_deactivate), - NULL, 0, NULL); + error = cyapa_write_bytes(dev, CMD_BOOT_STATUS, + bl_deactivate, sizeof(bl_deactivate)); if (error) goto done; } else { /* Magic */ - error = smbus_trans(bus, addr, CMD_BOOT_STATUS, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - bl_exit, sizeof(bl_exit), NULL, 0, NULL); + error = cyapa_write_bytes(dev, CMD_BOOT_STATUS, + bl_exit, sizeof(bl_exit)); if (error) goto done; } pause("cyapab1", (hz * 2) / 10); --retries; - error = smbus_trans(bus, addr, CMD_BOOT_STATUS, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, (void *)&boot, sizeof(boot), NULL); + error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, + (void *)&boot, sizeof(boot)); if (error) goto done; } @@ -381,9 +396,8 @@ /* Check identity */ if (cap) { - error = smbus_trans(bus, addr, CMD_QUERY_CAPABILITIES, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, (void *)cap, sizeof(*cap), NULL); + error = cyapa_read_bytes(dev, CMD_QUERY_CAPABILITIES, + (void *)cap, sizeof(*cap)); if (strncmp(cap->prod_ida, "CYTRA", 5) != 0) { device_printf(dev, "Product ID \"%5.5s\" mismatch\n", @@ -391,9 +405,8 @@ error = ENXIO; } } - error = smbus_trans(bus, addr, CMD_BOOT_STATUS, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, (void *)&boot, sizeof(boot), NULL); + error = cyapa_read_bytes(dev, CMD_BOOT_STATUS, + (void *)&boot, sizeof(boot)); if (probe == 0) /* official init */ device_printf(dev, "cyapa init status %02x\n", boot.stat); @@ -452,16 +465,16 @@ int addr; int error; - addr = smbus_get_addr(dev); + addr = iicbus_get_addr(dev); /* * 0x67 - cypress trackpad on the acer c720 * (other devices might use other ids). */ - if (addr != 0x67) + if (addr != 0xce) return (ENXIO); - error = init_device(dev, &cap, addr, 1); + error = init_device(dev, &cap, 1); if (error != 0) return (ENXIO); @@ -482,15 +495,14 @@ sc->reporting_mode = 1; unit = device_get_unit(dev); - addr = smbus_get_addr(dev); + addr = iicbus_get_addr(dev); - if (init_device(dev, &cap, addr, 0)) + if (init_device(dev, &cap, 0)) return (ENXIO); mtx_init(&sc->mutex, "cyapa", NULL, MTX_DEF); sc->dev = dev; - sc->addr = addr; knlist_init_mtx(&sc->selinfo.si_note, &sc->mutex); @@ -1159,7 +1171,7 @@ { struct cyapa_softc *sc; struct cyapa_regs regs; - device_t bus; /* smbus */ + device_t bus; /* iicbus */ int error; int freq; int isidle; @@ -1180,12 +1192,10 @@ while (!sc->detaching) { cyapa_unlock(sc); - error = smbus_request_bus(bus, sc->dev, SMB_WAIT); + error = iicbus_request_bus(bus, sc->dev, IIC_WAIT); if (error == 0) { - error = smbus_trans(bus, sc->addr, CMD_DEV_STATUS, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, - (void *)®s, sizeof(regs), NULL); + error = cyapa_read_bytes(sc->dev, CMD_DEV_STATUS, + (void *)®s, sizeof(regs)); if (error == 0) { isidle = cyapa_raw_input(sc, ®s, freq); } @@ -1200,9 +1210,9 @@ (unsigned)(ticks - last_reset) > TIME_TO_RESET)) { cyapa_reset = 0; last_reset = ticks; - init_device(sc->dev, NULL, sc->addr, 2); + init_device(sc->dev, NULL, 2); } - smbus_release_bus(bus, sc->dev); + iicbus_release_bus(bus, sc->dev); } pause("cyapw", hz / freq); ++sc->poll_ticks; @@ -1531,18 +1541,16 @@ int error; bus = device_get_parent(sc->dev); - error = smbus_request_bus(bus, sc->dev, SMB_WAIT); + error = iicbus_request_bus(bus, sc->dev, IIC_WAIT); if (error == 0) { - error = smbus_trans(bus, sc->addr, CMD_POWER_MODE, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, (void *)&data, 1, NULL); + error = cyapa_read_bytes(sc->dev, CMD_POWER_MODE, + &data, 1); data = (data & ~0xFC) | mode; if (error == 0) { - error = smbus_trans(bus, sc->addr, CMD_POWER_MODE, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - (void *)&data, 1, NULL, 0, NULL); + error = cyapa_write_bytes(sc->dev, CMD_POWER_MODE, + &data, 1); } - smbus_release_bus(bus, sc->dev); + iicbus_release_bus(bus, sc->dev); } } @@ -1697,6 +1705,6 @@ return (delta); } -DRIVER_MODULE(cyapa, smbus, cyapa_driver, cyapa_devclass, NULL, NULL); -MODULE_DEPEND(cyapa, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +DRIVER_MODULE(cyapa, iicbus, cyapa_driver, cyapa_devclass, NULL, NULL); +MODULE_DEPEND(cyapa, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); MODULE_VERSION(cyapa, 1); Index: head/sys/dev/ichiic/ig4_iic.c =================================================================== --- head/sys/dev/ichiic/ig4_iic.c +++ head/sys/dev/ichiic/ig4_iic.c @@ -61,6 +61,8 @@ #include #include #include +#include +#include #include #include @@ -120,7 +122,7 @@ reg_write(sc, IG4_REG_INTR_MASK, 0); reg_write(sc, IG4_REG_I2C_EN, ctl); - error = SMB_ETIMEOUT; + error = IIC_ETIMEOUT; for (retry = 100; retry > 0; --retry) { v = reg_read(sc, IG4_REG_ENABLE_STATUS); @@ -148,7 +150,7 @@ u_int count_us = 0; u_int limit_us = 25000; /* 25ms */ - error = SMB_ETIMEOUT; + error = IIC_ETIMEOUT; for (;;) { /* @@ -484,6 +486,236 @@ } /* + * IICBUS API FUNCTIONS + */ +static int +ig4iic_xfer_start(ig4iic_softc_t *sc, uint16_t slave) +{ + /* XXX 10-bit address support? */ + set_slave_addr(sc, slave >> 1, 0); + return (0); +} + +static int +ig4iic_read(ig4iic_softc_t *sc, uint8_t *buf, uint16_t len, + bool repeated_start, bool stop) +{ + uint32_t cmd; + uint16_t i; + int error; + + if (len == 0) + return (0); + + cmd = IG4_DATA_COMMAND_RD; + cmd |= repeated_start ? IG4_DATA_RESTART : 0; + cmd |= stop && len == 1 ? IG4_DATA_STOP : 0; + + /* Issue request for the first byte (could be last as well). */ + reg_write(sc, IG4_REG_DATA_CMD, cmd); + + for (i = 0; i < len; i++) { + /* + * Maintain a pipeline by queueing the allowance for the next + * read before waiting for the current read. + */ + cmd = IG4_DATA_COMMAND_RD; + if (i < len - 1) { + cmd = IG4_DATA_COMMAND_RD; + cmd |= stop && i == len - 2 ? IG4_DATA_STOP : 0; + reg_write(sc, IG4_REG_DATA_CMD, cmd); + } + error = wait_status(sc, IG4_STATUS_RX_NOTEMPTY); + if (error) + break; + buf[i] = data_read(sc); + } + + (void)reg_read(sc, IG4_REG_TX_ABRT_SOURCE); + return (error); +} + +static int +ig4iic_write(ig4iic_softc_t *sc, uint8_t *buf, uint16_t len, + bool repeated_start, bool stop) +{ + uint32_t cmd; + uint16_t i; + int error; + + if (len == 0) + return (0); + + cmd = repeated_start ? IG4_DATA_RESTART : 0; + for (i = 0; i < len; i++) { + error = wait_status(sc, IG4_STATUS_TX_NOTFULL); + if (error) + break; + cmd |= buf[i]; + cmd |= stop && i == len - 1 ? IG4_DATA_STOP : 0; + reg_write(sc, IG4_REG_DATA_CMD, cmd); + cmd = 0; + } + + (void)reg_read(sc, IG4_REG_TX_ABRT_SOURCE); + return (error); +} + +int +ig4iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + const char *reason = NULL; + uint32_t i; + int error; + int unit; + bool rpstart; + bool stop; + + /* + * The hardware interface imposes limits on allowed I2C messages. + * It is not possible to explicitly send a start or stop. + * They are automatically sent (or not sent, depending on the + * configuration) when a data byte is transferred. + * For this reason it's impossible to send a message with no data + * at all (like an SMBus quick message). + * The start condition is automatically generated after the stop + * condition, so it's impossible to not have a start after a stop. + * The repeated start condition is automatically sent if a change + * of the transfer direction happens, so it's impossible to have + * a change of direction without a (repeated) start. + * The repeated start can be forced even without the change of + * direction. + * Changing the target slave address requires resetting the hardware + * state, so it's impossible to do that without the stop followed + * by the start. + */ + for (i = 0; i < nmsgs; i++) { +#if 0 + if (i == 0 && (msgs[i].flags & IIC_M_NOSTART) != 0) { + reason = "first message without start"; + break; + } + if (i == nmsgs - 1 && (msgs[i].flags & IIC_M_NOSTOP) != 0) { + reason = "last message without stop"; + break; + } +#endif + if (msgs[i].len == 0) { + reason = "message with no data"; + break; + } + if (i > 0) { + if ((msgs[i].flags & IIC_M_NOSTART) != 0 && + (msgs[i - 1].flags & IIC_M_NOSTOP) == 0) { + reason = "stop not followed by start"; + break; + } + if ((msgs[i - 1].flags & IIC_M_NOSTOP) != 0 && + msgs[i].slave != msgs[i - 1].slave) { + reason = "change of slave without stop"; + break; + } + if ((msgs[i].flags & IIC_M_NOSTART) != 0 && + (msgs[i].flags & IIC_M_RD) != + (msgs[i - 1].flags & IIC_M_RD)) { + reason = "change of direction without repeated" + " start"; + break; + } + } + } + if (reason != NULL) { + if (bootverbose) + device_printf(dev, "%s\n", reason); + return (IIC_ENOTSUPP); + } + + sx_xlock(&sc->call_lock); + mtx_lock(&sc->io_lock); + + /* Debugging - dump registers. */ + if (ig4_dump) { + unit = device_get_unit(dev); + if (ig4_dump & (1 << unit)) { + ig4_dump &= ~(1 << unit); + ig4iic_dump(sc); + } + } + + /* + * Clear any previous abort condition that may have been holding + * the txfifo in reset. + */ + reg_read(sc, IG4_REG_CLR_TX_ABORT); + + /* + * Clean out any previously received data. + */ + if (sc->rpos != sc->rnext && bootverbose) { + device_printf(sc->dev, "discarding %d bytes of spurious data\n", + sc->rnext - sc->rpos); + } + sc->rpos = 0; + sc->rnext = 0; + + rpstart = false; + error = 0; + for (i = 0; i < nmsgs; i++) { + if ((msgs[i].flags & IIC_M_NOSTART) == 0) { + error = ig4iic_xfer_start(sc, msgs[i].slave); + } else { + if (!sc->slave_valid || + (msgs[i].slave >> 1) != sc->last_slave) { + device_printf(dev, "start condition suppressed" + "but slave address is not set up"); + error = EINVAL; + break; + } + rpstart = false; + } + if (error != 0) + break; + + stop = (msgs[i].flags & IIC_M_NOSTOP) == 0; + if (msgs[i].flags & IIC_M_RD) + error = ig4iic_read(sc, msgs[i].buf, msgs[i].len, + rpstart, stop); + else + error = ig4iic_write(sc, msgs[i].buf, msgs[i].len, + rpstart, stop); + if (error != 0) + break; + + rpstart = !stop; + } + + mtx_unlock(&sc->io_lock); + sx_unlock(&sc->call_lock); + return (error); +} + +int +ig4iic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) +{ + ig4iic_softc_t *sc = device_get_softc(dev); + + sx_xlock(&sc->call_lock); + mtx_lock(&sc->io_lock); + + /* TODO handle speed configuration? */ + if (oldaddr != NULL) + *oldaddr = sc->last_slave << 1; + set_slave_addr(sc, addr >> 1, 0); + if (addr == IIC_UNKNOWN) + sc->slave_valid = false; + + mtx_unlock(&sc->io_lock); + sx_unlock(&sc->call_lock); + return (0); +} + +/* * SMBUS API FUNCTIONS * * Called from ig4iic_pci_attach/detach() @@ -549,9 +781,9 @@ IG4_CTL_RESTARTEN | IG4_CTL_SPEED_STD); - sc->smb = device_add_child(sc->dev, "smbus", -1); - if (sc->smb == NULL) { - device_printf(sc->dev, "smbus driver not found\n"); + sc->iicbus = device_add_child(sc->dev, "iicbus", -1); + if (sc->iicbus == NULL) { + device_printf(sc->dev, "iicbus driver not found\n"); error = ENXIO; goto done; } @@ -624,15 +856,15 @@ if (error) return (error); } - if (sc->smb) - device_delete_child(sc->dev, sc->smb); + if (sc->iicbus) + device_delete_child(sc->dev, sc->iicbus); if (sc->intr_handle) bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle); sx_xlock(&sc->call_lock); mtx_lock(&sc->io_lock); - sc->smb = NULL; + sc->iicbus = NULL; sc->intr_handle = NULL; reg_write(sc, IG4_REG_INTR_MASK, 0); set_controller(sc, 0); @@ -976,4 +1208,4 @@ } #undef REGDUMP -DRIVER_MODULE(smbus, ig4iic, smbus_driver, smbus_devclass, NULL, NULL); +DRIVER_MODULE(iicbus, ig4iic, iicbus_driver, iicbus_devclass, NULL, NULL); Index: head/sys/dev/ichiic/ig4_pci.c =================================================================== --- head/sys/dev/ichiic/ig4_pci.c +++ head/sys/dev/ichiic/ig4_pci.c @@ -60,6 +60,7 @@ #include #include #include +#include #include "smbus_if.h" @@ -180,6 +181,10 @@ DEVMETHOD(smbus_bread, ig4iic_smb_bread), DEVMETHOD(smbus_trans, ig4iic_smb_trans), + DEVMETHOD(iicbus_transfer, ig4iic_transfer), + DEVMETHOD(iicbus_reset, ig4iic_reset), + DEVMETHOD(iicbus_callback, iicbus_null_callback), + DEVMETHOD_END }; @@ -191,7 +196,9 @@ static devclass_t ig4iic_pci_devclass; -DRIVER_MODULE(ig4iic, pci, ig4iic_pci_driver, ig4iic_pci_devclass, 0, 0); +DRIVER_MODULE_ORDERED(ig4iic, pci, ig4iic_pci_driver, ig4iic_pci_devclass, 0, 0, + SI_ORDER_ANY); MODULE_DEPEND(ig4iic, pci, 1, 1, 1); MODULE_DEPEND(ig4iic, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +MODULE_DEPEND(ig4iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); MODULE_VERSION(ig4iic, 1); Index: head/sys/dev/ichiic/ig4_var.h =================================================================== --- head/sys/dev/ichiic/ig4_var.h +++ head/sys/dev/ichiic/ig4_var.h @@ -42,6 +42,7 @@ #include "device_if.h" #include "pci_if.h" #include "smbus_if.h" +#include "iicbus_if.h" #define IG4_RBUFSIZE 128 #define IG4_RBUFMASK (IG4_RBUFSIZE - 1) @@ -51,7 +52,7 @@ struct ig4iic_softc { device_t dev; struct intr_config_hook enum_hook; - device_t smb; + device_t iicbus; struct resource *regs_res; int regs_rid; struct resource *intr_res; @@ -115,5 +116,7 @@ extern smbus_bwrite_t ig4iic_smb_bwrite; extern smbus_bread_t ig4iic_smb_bread; extern smbus_trans_t ig4iic_smb_trans; +extern iicbus_transfer_t ig4iic_transfer; +extern iicbus_reset_t ig4iic_reset; #endif Index: head/sys/dev/iicbus/iicbus.c =================================================================== --- head/sys/dev/iicbus/iicbus.c +++ head/sys/dev/iicbus/iicbus.c @@ -208,7 +208,9 @@ default: return (EINVAL); case IICBUS_IVAR_ADDR: - return (EINVAL); + if (devi->addr != 0) + return (EINVAL); + devi->addr = value; case IICBUS_IVAR_NOSTOP: devi->nostop = value; break; Index: head/sys/dev/isl/isl.c =================================================================== --- head/sys/dev/isl/isl.c +++ head/sys/dev/isl/isl.c @@ -52,14 +52,12 @@ #include #include #include -#include -#include -#include -#include +#include +#include #include -#include "smbus_if.h" +#include "iicbus_if.h" #include "bus_if.h" #include "device_if.h" @@ -71,46 +69,58 @@ struct isl_softc { device_t dev; - int addr; - struct sx isl_sx; }; /* Returns < 0 on problem. */ -static int isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask); +static int isl_read_sensor(device_t dev, uint8_t cmd_mask); + +static int +isl_read_byte(device_t dev, uint8_t reg, uint8_t *val) +{ + uint16_t addr = iicbus_get_addr(dev); + struct iic_msg msgs[] = { + { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, + { addr, IIC_M_RD, 1, val }, + }; + + return (iicbus_transfer(dev, msgs, nitems(msgs))); +} + +static int +isl_write_byte(device_t dev, uint8_t reg, uint8_t val) +{ + uint16_t addr = iicbus_get_addr(dev); + uint8_t bytes[] = { reg, val }; + struct iic_msg msgs[] = { + { addr, IIC_M_WR, nitems(bytes), bytes }, + }; + + return (iicbus_transfer(dev, msgs, nitems(msgs))); +} /* * Initialize the device */ static int -init_device(device_t dev, int addr, int probe) +init_device(device_t dev, int probe) { - static char bl_init[] = { 0x00 }; - - device_t bus; int error; - bus = device_get_parent(dev); /* smbus */ - /* * init procedure: send 0x00 to test ref and cmd reg 1 */ - error = smbus_trans(bus, addr, REG_TEST, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - bl_init, sizeof(bl_init), NULL, 0, NULL); + error = isl_write_byte(dev, REG_TEST, 0); if (error) goto done; - - error = smbus_trans(bus, addr, REG_CMD1, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - bl_init, sizeof(bl_init), NULL, 0, NULL); + error = isl_write_byte(dev, REG_CMD1, 0); if (error) goto done; pause("islinit", hz/100); done: - if (error) + if (error && !probe) device_printf(dev, "Unable to initialize\n"); return (error); } @@ -138,27 +148,33 @@ sizeof(struct isl_softc), }; +#if 0 +static void +isl_identify(driver_t *driver, device_t parent) +{ + + if (device_find_child(parent, "asl", -1)) { + if (bootverbose) + printf("asl: device(s) already created\n"); + return; + } + + /* Check if we can communicate to our slave. */ + if (init_device(dev, 0x88, 1) == 0) + BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "isl", -1); +} +#endif + static int isl_probe(device_t dev) { - int addr; - int error; - - addr = smbus_get_addr(dev); + uint32_t addr = iicbus_get_addr(dev); - /* - * 0x44 - isl ambient light sensor on the acer c720. - * (other devices might use other ids). - */ - if (addr != 0x44) + if (addr != 0x88) return (ENXIO); - - error = init_device(dev, addr, 1); - if (error) + if (init_device(dev, 1) != 0) return (ENXIO); - device_set_desc(dev, "ISL Digital Ambient Light Sensor"); - return (BUS_PROBE_VENDOR); } @@ -168,36 +184,28 @@ struct isl_softc *sc; struct sysctl_ctx_list *sysctl_ctx; struct sysctl_oid *sysctl_tree; - int addr; int use_als; int use_ir; int use_prox; sc = device_get_softc(dev); + sc->dev = dev; - if (!sc) - return (ENOMEM); - - addr = smbus_get_addr(dev); - - if (init_device(dev, addr, 0)) + if (init_device(dev, 0) != 0) return (ENXIO); sx_init(&sc->isl_sx, "ISL read lock"); - sc->dev = dev; - sc->addr = addr; - sysctl_ctx = device_get_sysctl_ctx(dev); sysctl_tree = device_get_sysctl_tree(dev); - use_als = isl_read_sensor(dev, addr, CMD1_MASK_ALS_ONCE) >= 0; - use_ir = isl_read_sensor(dev, addr, CMD1_MASK_IR_ONCE) >= 0; - use_prox = isl_read_sensor(dev, addr, CMD1_MASK_PROX_ONCE) >= 0; + use_als = isl_read_sensor(dev, CMD1_MASK_ALS_ONCE) >= 0; + use_ir = isl_read_sensor(dev, CMD1_MASK_IR_ONCE) >= 0; + use_prox = isl_read_sensor(dev, CMD1_MASK_PROX_ONCE) >= 0; if (use_als) { SYSCTL_ADD_PROC(sysctl_ctx, - SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, + SYSCTL_CHILDREN(sysctl_tree), OID_AUTO, "als", CTLTYPE_INT | CTLFLAG_RD, sc, ISL_METHOD_ALS, isl_sysctl, "I", "Current ALS sensor read-out"); @@ -252,7 +260,6 @@ static int ranges[] = { 1000, 4000, 16000, 64000}; struct isl_softc *sc; - device_t bus; uint8_t rbyte; int arg; int resolution; @@ -262,10 +269,7 @@ arg = -1; sx_xlock(&sc->isl_sx); - bus = device_get_parent(sc->dev); /* smbus */ - if (smbus_trans(bus, sc->addr, REG_CMD2, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, &rbyte, sizeof(rbyte), NULL)) { + if (isl_read_byte(sc->dev, REG_CMD2, &rbyte) != 0) { sx_xunlock(&sc->isl_sx); return (-1); } @@ -275,16 +279,14 @@ switch (oidp->oid_arg2) { case ISL_METHOD_ALS: - arg = (isl_read_sensor(sc->dev, sc->addr, + arg = (isl_read_sensor(sc->dev, CMD1_MASK_ALS_ONCE) * range) >> resolution; break; case ISL_METHOD_IR: - arg = isl_read_sensor(sc->dev, sc->addr, - CMD1_MASK_IR_ONCE); + arg = isl_read_sensor(sc->dev, CMD1_MASK_IR_ONCE); break; case ISL_METHOD_PROX: - arg = isl_read_sensor(sc->dev, sc->addr, - CMD1_MASK_PROX_ONCE); + arg = isl_read_sensor(sc->dev, CMD1_MASK_PROX_ONCE); break; case ISL_METHOD_RESOLUTION: arg = (1 << resolution); @@ -300,18 +302,13 @@ } static int -isl_read_sensor(device_t dev, int addr, uint8_t cmd_mask) +isl_read_sensor(device_t dev, uint8_t cmd_mask) { - device_t bus; uint8_t rbyte; uint8_t cmd; int ret; - bus = device_get_parent(dev); /* smbus */ - - if (smbus_trans(bus, addr, REG_CMD1, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, &rbyte, sizeof(rbyte), NULL)) { + if (isl_read_byte(dev, REG_CMD1, &rbyte) != 0) { device_printf(dev, "Couldn't read first byte before issuing command %d\n", cmd_mask); @@ -319,27 +316,21 @@ } cmd = (rbyte & 0x1f) | cmd_mask; - if (smbus_trans(bus, addr, REG_CMD1, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - &cmd, sizeof(cmd), NULL, 0, NULL)) { + if (isl_write_byte(dev, REG_CMD1, cmd) != 0) { device_printf(dev, "Couldn't write command %d\n", cmd_mask); return (-1); } pause("islconv", hz/10); - if (smbus_trans(bus, addr, REG_DATA1, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, &rbyte, sizeof(rbyte), NULL)) { + if (isl_read_byte(dev, REG_DATA1, &rbyte) != 0) { device_printf(dev, "Couldn't read first byte after command %d\n", cmd_mask); return (-1); } ret = rbyte; - if (smbus_trans(bus, addr, REG_DATA2, - SMB_TRANS_NOCNT | SMB_TRANS_7BIT, - NULL, 0, &rbyte, sizeof(rbyte), NULL)) { + if (isl_read_byte(dev, REG_DATA2, &rbyte) != 0) { device_printf(dev, "Couldn't read second byte after command %d\n", cmd_mask); return (-1); } @@ -348,6 +339,6 @@ return (ret); } -DRIVER_MODULE(isl, smbus, isl_driver, isl_devclass, NULL, NULL); -MODULE_DEPEND(isl, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +DRIVER_MODULE(isl, iicbus, isl_driver, isl_devclass, NULL, NULL); +MODULE_DEPEND(isl, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); MODULE_VERSION(isl, 1); Index: head/sys/modules/Makefile =================================================================== --- head/sys/modules/Makefile +++ head/sys/modules/Makefile @@ -73,6 +73,7 @@ cd9660_iconv \ ${_ce} \ ${_cfi} \ + ${_chromebook_platform} \ ${_ciss} \ cloudabi \ ${_cloudabi32} \ @@ -604,6 +605,7 @@ _arcmsr= arcmsr _asmc= asmc _ciss= ciss +_chromebook_platform= chromebook_platform _cmx= cmx _coretemp= coretemp .if ${MK_SOURCELESS_HOST} != "no" Index: head/sys/modules/chromebook_platform/Makefile =================================================================== --- head/sys/modules/chromebook_platform/Makefile +++ head/sys/modules/chromebook_platform/Makefile @@ -0,0 +1,7 @@ +#$FreeBSD$ + +.PATH: ${.CURDIR}/../../dev/chromebook_platform +KMOD = chromebook_platform +SRCS = chromebook_platform.c bus_if.h device_if.h pci_if.h + +.include Index: head/sys/modules/i2c/controllers/ichiic/Makefile =================================================================== --- head/sys/modules/i2c/controllers/ichiic/Makefile +++ head/sys/modules/i2c/controllers/ichiic/Makefile @@ -2,7 +2,7 @@ .PATH: ${.CURDIR}/../../../../dev/ichiic KMOD = ig4 -SRCS = device_if.h bus_if.h iicbb_if.h pci_if.h smbus_if.h \ +SRCS = device_if.h bus_if.h iicbus_if.h pci_if.h smbus_if.h \ ig4_iic.c ig4_pci.c ig4_reg.h ig4_var.h .include Index: head/sys/modules/i2c/cyapa/Makefile =================================================================== --- head/sys/modules/i2c/cyapa/Makefile +++ head/sys/modules/i2c/cyapa/Makefile @@ -2,6 +2,6 @@ .PATH: ${.CURDIR}/../../../dev/cyapa KMOD = cyapa -SRCS = cyapa.c device_if.h bus_if.h smbus_if.h vnode_if.h +SRCS = cyapa.c device_if.h bus_if.h iicbus_if.h vnode_if.h .include Index: head/sys/modules/i2c/isl/Makefile =================================================================== --- head/sys/modules/i2c/isl/Makefile +++ head/sys/modules/i2c/isl/Makefile @@ -2,6 +2,6 @@ .PATH: ${.CURDIR}/../../../dev/isl KMOD = isl -SRCS = isl.c device_if.h bus_if.h smbus_if.h vnode_if.h +SRCS = isl.c device_if.h bus_if.h iicbus_if.h .include