171d51719SMichael Gmelin /* 271d51719SMichael Gmelin * Copyright (c) 2014 The DragonFly Project. All rights reserved. 371d51719SMichael Gmelin * 471d51719SMichael Gmelin * This code is derived from software contributed to The DragonFly Project 571d51719SMichael Gmelin * by Matthew Dillon <dillon@backplane.com> and was subsequently ported 671d51719SMichael Gmelin * to FreeBSD by Michael Gmelin <freebsd@grem.de> 771d51719SMichael Gmelin * 871d51719SMichael Gmelin * Redistribution and use in source and binary forms, with or without 971d51719SMichael Gmelin * modification, are permitted provided that the following conditions 1071d51719SMichael Gmelin * are met: 1171d51719SMichael Gmelin * 1271d51719SMichael Gmelin * 1. Redistributions of source code must retain the above copyright 1371d51719SMichael Gmelin * notice, this list of conditions and the following disclaimer. 1471d51719SMichael Gmelin * 2. Redistributions in binary form must reproduce the above copyright 1571d51719SMichael Gmelin * notice, this list of conditions and the following disclaimer in 1671d51719SMichael Gmelin * the documentation and/or other materials provided with the 1771d51719SMichael Gmelin * distribution. 1871d51719SMichael Gmelin * 3. Neither the name of The DragonFly Project nor the names of its 1971d51719SMichael Gmelin * contributors may be used to endorse or promote products derived 2071d51719SMichael Gmelin * from this software without specific, prior written permission. 2171d51719SMichael Gmelin * 2271d51719SMichael Gmelin * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2371d51719SMichael Gmelin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2471d51719SMichael Gmelin * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 2571d51719SMichael Gmelin * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 2671d51719SMichael Gmelin * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2771d51719SMichael Gmelin * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 2871d51719SMichael Gmelin * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2971d51719SMichael Gmelin * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 3071d51719SMichael Gmelin * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3171d51719SMichael Gmelin * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 3271d51719SMichael Gmelin * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3371d51719SMichael Gmelin * SUCH DAMAGE. 3471d51719SMichael Gmelin */ 3571d51719SMichael Gmelin 3671d51719SMichael Gmelin #include <sys/cdefs.h> 3771d51719SMichael Gmelin __FBSDID("$FreeBSD$"); 3871d51719SMichael Gmelin 3971d51719SMichael Gmelin /* 40eb6befbaSAndriy Gapon * Intel fourth generation mobile cpus integrated I2C device. 4171d51719SMichael Gmelin * 4271d51719SMichael Gmelin * See ig4_reg.h for datasheet reference and notes. 434cd6abddSMichael Gmelin * See ig4_var.h for locking semantics. 4471d51719SMichael Gmelin */ 4571d51719SMichael Gmelin 4671d51719SMichael Gmelin #include <sys/param.h> 4771d51719SMichael Gmelin #include <sys/systm.h> 4871d51719SMichael Gmelin #include <sys/kernel.h> 4971d51719SMichael Gmelin #include <sys/module.h> 5071d51719SMichael Gmelin #include <sys/errno.h> 51c59aca57SVladimir Kondratyev #include <sys/kdb.h> 5271d51719SMichael Gmelin #include <sys/lock.h> 5371d51719SMichael Gmelin #include <sys/mutex.h> 54c59aca57SVladimir Kondratyev #include <sys/proc.h> 554cd6abddSMichael Gmelin #include <sys/sx.h> 5671d51719SMichael Gmelin #include <sys/syslog.h> 5771d51719SMichael Gmelin #include <sys/bus.h> 5871d51719SMichael Gmelin #include <sys/sysctl.h> 5971d51719SMichael Gmelin 6071d51719SMichael Gmelin #include <machine/bus.h> 6171d51719SMichael Gmelin #include <sys/rman.h> 6271d51719SMichael Gmelin 6371d51719SMichael Gmelin #include <dev/pci/pcivar.h> 6471d51719SMichael Gmelin #include <dev/pci/pcireg.h> 65448897d3SAndriy Gapon #include <dev/iicbus/iicbus.h> 66448897d3SAndriy Gapon #include <dev/iicbus/iiconf.h> 6771d51719SMichael Gmelin 6871d51719SMichael Gmelin #include <dev/ichiic/ig4_reg.h> 6971d51719SMichael Gmelin #include <dev/ichiic/ig4_var.h> 7071d51719SMichael Gmelin 7171d51719SMichael Gmelin #define TRANS_NORMAL 1 7271d51719SMichael Gmelin #define TRANS_PCALL 2 7371d51719SMichael Gmelin #define TRANS_BLOCK 3 7471d51719SMichael Gmelin 75c59aca57SVladimir Kondratyev #define DO_POLL(sc) (cold || kdb_active || SCHEDULER_STOPPED()) 76c59aca57SVladimir Kondratyev 7771d51719SMichael Gmelin static void ig4iic_start(void *xdev); 7871d51719SMichael Gmelin static void ig4iic_intr(void *cookie); 7971d51719SMichael Gmelin static void ig4iic_dump(ig4iic_softc_t *sc); 8071d51719SMichael Gmelin 8171d51719SMichael Gmelin static int ig4_dump; 8212e413beSMichael Gmelin SYSCTL_INT(_debug, OID_AUTO, ig4_dump, CTLFLAG_RW, 8312e413beSMichael Gmelin &ig4_dump, 0, "Dump controller registers"); 8471d51719SMichael Gmelin 8571d51719SMichael Gmelin /* 8671d51719SMichael Gmelin * Low-level inline support functions 8771d51719SMichael Gmelin */ 8871d51719SMichael Gmelin static __inline void 8971d51719SMichael Gmelin reg_write(ig4iic_softc_t *sc, uint32_t reg, uint32_t value) 9071d51719SMichael Gmelin { 9171d51719SMichael Gmelin bus_write_4(sc->regs_res, reg, value); 9271d51719SMichael Gmelin bus_barrier(sc->regs_res, reg, 4, BUS_SPACE_BARRIER_WRITE); 9371d51719SMichael Gmelin } 9471d51719SMichael Gmelin 9571d51719SMichael Gmelin static __inline uint32_t 9671d51719SMichael Gmelin reg_read(ig4iic_softc_t *sc, uint32_t reg) 9771d51719SMichael Gmelin { 9871d51719SMichael Gmelin uint32_t value; 9971d51719SMichael Gmelin 10071d51719SMichael Gmelin bus_barrier(sc->regs_res, reg, 4, BUS_SPACE_BARRIER_READ); 10171d51719SMichael Gmelin value = bus_read_4(sc->regs_res, reg); 10271d51719SMichael Gmelin return (value); 10371d51719SMichael Gmelin } 10471d51719SMichael Gmelin 10521e459c6SVladimir Kondratyev static void 10621e459c6SVladimir Kondratyev set_intr_mask(ig4iic_softc_t *sc, uint32_t val) 10721e459c6SVladimir Kondratyev { 10821e459c6SVladimir Kondratyev if (sc->intr_mask != val) { 10921e459c6SVladimir Kondratyev reg_write(sc, IG4_REG_INTR_MASK, val); 11021e459c6SVladimir Kondratyev sc->intr_mask = val; 11121e459c6SVladimir Kondratyev } 11221e459c6SVladimir Kondratyev } 11321e459c6SVladimir Kondratyev 11471d51719SMichael Gmelin /* 11571d51719SMichael Gmelin * Enable or disable the controller and wait for the controller to acknowledge 11671d51719SMichael Gmelin * the state change. 11771d51719SMichael Gmelin */ 11871d51719SMichael Gmelin static int 11971d51719SMichael Gmelin set_controller(ig4iic_softc_t *sc, uint32_t ctl) 12071d51719SMichael Gmelin { 12171d51719SMichael Gmelin int retry; 12271d51719SMichael Gmelin int error; 12371d51719SMichael Gmelin uint32_t v; 12471d51719SMichael Gmelin 1250ba5622dSMichael Gmelin /* 1260ba5622dSMichael Gmelin * When the controller is enabled, interrupt on STOP detect 1270ba5622dSMichael Gmelin * or receive character ready and clear pending interrupts. 1280ba5622dSMichael Gmelin */ 12921e459c6SVladimir Kondratyev set_intr_mask(sc, 0); 13021e459c6SVladimir Kondratyev if (ctl & IG4_I2C_ENABLE) 1310ba5622dSMichael Gmelin reg_read(sc, IG4_REG_CLR_INTR); 1320ba5622dSMichael Gmelin 13371d51719SMichael Gmelin reg_write(sc, IG4_REG_I2C_EN, ctl); 134448897d3SAndriy Gapon error = IIC_ETIMEOUT; 13571d51719SMichael Gmelin 13671d51719SMichael Gmelin for (retry = 100; retry > 0; --retry) { 13771d51719SMichael Gmelin v = reg_read(sc, IG4_REG_ENABLE_STATUS); 13871d51719SMichael Gmelin if (((v ^ ctl) & IG4_I2C_ENABLE) == 0) { 13971d51719SMichael Gmelin error = 0; 14071d51719SMichael Gmelin break; 14171d51719SMichael Gmelin } 14285cd895fSVladimir Kondratyev pause("i2cslv", 1); 14371d51719SMichael Gmelin } 14471d51719SMichael Gmelin return (error); 14571d51719SMichael Gmelin } 14671d51719SMichael Gmelin 14771d51719SMichael Gmelin /* 14871d51719SMichael Gmelin * Wait up to 25ms for the requested status using a 25uS polling loop. 14971d51719SMichael Gmelin */ 15071d51719SMichael Gmelin static int 15171d51719SMichael Gmelin wait_status(ig4iic_softc_t *sc, uint32_t status) 15271d51719SMichael Gmelin { 15371d51719SMichael Gmelin uint32_t v; 15471d51719SMichael Gmelin int error; 15571d51719SMichael Gmelin int txlvl = -1; 15671d51719SMichael Gmelin u_int count_us = 0; 15771d51719SMichael Gmelin u_int limit_us = 25000; /* 25ms */ 15871d51719SMichael Gmelin 159448897d3SAndriy Gapon error = IIC_ETIMEOUT; 16071d51719SMichael Gmelin 16171d51719SMichael Gmelin for (;;) { 16271d51719SMichael Gmelin /* 16371d51719SMichael Gmelin * Check requested status 16471d51719SMichael Gmelin */ 16571d51719SMichael Gmelin v = reg_read(sc, IG4_REG_I2C_STA); 16671d51719SMichael Gmelin if (v & status) { 16771d51719SMichael Gmelin error = 0; 16871d51719SMichael Gmelin break; 16971d51719SMichael Gmelin } 17071d51719SMichael Gmelin 17171d51719SMichael Gmelin /* 17271d51719SMichael Gmelin * When waiting for the transmit FIFO to become empty, 17371d51719SMichael Gmelin * reset the timeout if we see a change in the transmit 17471d51719SMichael Gmelin * FIFO level as progress is being made. 17571d51719SMichael Gmelin */ 17671d51719SMichael Gmelin if (status & IG4_STATUS_TX_EMPTY) { 17771d51719SMichael Gmelin v = reg_read(sc, IG4_REG_TXFLR) & IG4_FIFOLVL_MASK; 17871d51719SMichael Gmelin if (txlvl != v) { 17971d51719SMichael Gmelin txlvl = v; 18071d51719SMichael Gmelin count_us = 0; 18171d51719SMichael Gmelin } 18271d51719SMichael Gmelin } 18371d51719SMichael Gmelin 18471d51719SMichael Gmelin /* 18571d51719SMichael Gmelin * Stop if we've run out of time. 18671d51719SMichael Gmelin */ 18771d51719SMichael Gmelin if (count_us >= limit_us) 18871d51719SMichael Gmelin break; 18971d51719SMichael Gmelin 19071d51719SMichael Gmelin /* 19171d51719SMichael Gmelin * When waiting for receive data let the interrupt do its 19271d51719SMichael Gmelin * work, otherwise poll with the lock held. 19371d51719SMichael Gmelin */ 194c59aca57SVladimir Kondratyev if ((status & IG4_STATUS_RX_NOTEMPTY) && !DO_POLL(sc)) { 195733d657aSVladimir Kondratyev mtx_lock(&sc->io_lock); 19621e459c6SVladimir Kondratyev set_intr_mask(sc, IG4_INTR_STOP_DET | IG4_INTR_RX_FULL); 1974cd6abddSMichael Gmelin mtx_sleep(sc, &sc->io_lock, 0, "i2cwait", 19871d51719SMichael Gmelin (hz + 99) / 100); /* sleep up to 10ms */ 19921e459c6SVladimir Kondratyev set_intr_mask(sc, 0); 200733d657aSVladimir Kondratyev mtx_unlock(&sc->io_lock); 20171d51719SMichael Gmelin count_us += 10000; 20271d51719SMichael Gmelin } else { 20371d51719SMichael Gmelin DELAY(25); 20471d51719SMichael Gmelin count_us += 25; 20571d51719SMichael Gmelin } 20671d51719SMichael Gmelin } 20771d51719SMichael Gmelin 20871d51719SMichael Gmelin return (error); 20971d51719SMichael Gmelin } 21071d51719SMichael Gmelin 21171d51719SMichael Gmelin /* 21271d51719SMichael Gmelin * Set the slave address. The controller must be disabled when 21371d51719SMichael Gmelin * changing the address. 21471d51719SMichael Gmelin * 21571d51719SMichael Gmelin * This operation does not issue anything to the I2C bus but sets 21671d51719SMichael Gmelin * the target address for when the controller later issues a START. 21771d51719SMichael Gmelin */ 21871d51719SMichael Gmelin static void 219e3d25549SAndriy Gapon set_slave_addr(ig4iic_softc_t *sc, uint8_t slave) 22071d51719SMichael Gmelin { 22171d51719SMichael Gmelin uint32_t tar; 22271d51719SMichael Gmelin uint32_t ctl; 22371d51719SMichael Gmelin int use_10bit; 22471d51719SMichael Gmelin 22571d51719SMichael Gmelin use_10bit = 0; 22671d51719SMichael Gmelin if (sc->slave_valid && sc->last_slave == slave && 22771d51719SMichael Gmelin sc->use_10bit == use_10bit) { 22871d51719SMichael Gmelin return; 22971d51719SMichael Gmelin } 23071d51719SMichael Gmelin sc->use_10bit = use_10bit; 23171d51719SMichael Gmelin 23271d51719SMichael Gmelin /* 23371d51719SMichael Gmelin * Wait for TXFIFO to drain before disabling the controller. 23471d51719SMichael Gmelin * 23571d51719SMichael Gmelin * If a write message has not been completed it's really a 23671d51719SMichael Gmelin * programming error, but for now in that case issue an extra 23771d51719SMichael Gmelin * byte + STOP. 23871d51719SMichael Gmelin * 23971d51719SMichael Gmelin * If a read message has not been completed it's also a programming 24071d51719SMichael Gmelin * error, for now just ignore it. 24171d51719SMichael Gmelin */ 24271d51719SMichael Gmelin wait_status(sc, IG4_STATUS_TX_NOTFULL); 24371d51719SMichael Gmelin if (sc->write_started) { 24471d51719SMichael Gmelin reg_write(sc, IG4_REG_DATA_CMD, IG4_DATA_STOP); 24571d51719SMichael Gmelin sc->write_started = 0; 24671d51719SMichael Gmelin } 24771d51719SMichael Gmelin if (sc->read_started) 24871d51719SMichael Gmelin sc->read_started = 0; 24971d51719SMichael Gmelin wait_status(sc, IG4_STATUS_TX_EMPTY); 25071d51719SMichael Gmelin 25171d51719SMichael Gmelin set_controller(sc, 0); 25271d51719SMichael Gmelin ctl = reg_read(sc, IG4_REG_CTL); 25371d51719SMichael Gmelin ctl &= ~IG4_CTL_10BIT; 25471d51719SMichael Gmelin ctl |= IG4_CTL_RESTARTEN; 25571d51719SMichael Gmelin 25671d51719SMichael Gmelin tar = slave; 25771d51719SMichael Gmelin if (sc->use_10bit) { 25871d51719SMichael Gmelin tar |= IG4_TAR_10BIT; 25971d51719SMichael Gmelin ctl |= IG4_CTL_10BIT; 26071d51719SMichael Gmelin } 26171d51719SMichael Gmelin reg_write(sc, IG4_REG_CTL, ctl); 26271d51719SMichael Gmelin reg_write(sc, IG4_REG_TAR_ADD, tar); 26371d51719SMichael Gmelin set_controller(sc, IG4_I2C_ENABLE); 26471d51719SMichael Gmelin sc->slave_valid = 1; 26571d51719SMichael Gmelin sc->last_slave = slave; 26671d51719SMichael Gmelin } 26771d51719SMichael Gmelin 26871d51719SMichael Gmelin /* 269448897d3SAndriy Gapon * IICBUS API FUNCTIONS 270448897d3SAndriy Gapon */ 271448897d3SAndriy Gapon static int 272448897d3SAndriy Gapon ig4iic_xfer_start(ig4iic_softc_t *sc, uint16_t slave) 273448897d3SAndriy Gapon { 274e3d25549SAndriy Gapon set_slave_addr(sc, slave >> 1); 275448897d3SAndriy Gapon return (0); 276448897d3SAndriy Gapon } 277448897d3SAndriy Gapon 278448897d3SAndriy Gapon static int 279448897d3SAndriy Gapon ig4iic_read(ig4iic_softc_t *sc, uint8_t *buf, uint16_t len, 280448897d3SAndriy Gapon bool repeated_start, bool stop) 281448897d3SAndriy Gapon { 282448897d3SAndriy Gapon uint32_t cmd; 283448897d3SAndriy Gapon uint16_t i; 284448897d3SAndriy Gapon int error; 285448897d3SAndriy Gapon 286448897d3SAndriy Gapon if (len == 0) 287448897d3SAndriy Gapon return (0); 288448897d3SAndriy Gapon 289448897d3SAndriy Gapon cmd = IG4_DATA_COMMAND_RD; 290448897d3SAndriy Gapon cmd |= repeated_start ? IG4_DATA_RESTART : 0; 291448897d3SAndriy Gapon cmd |= stop && len == 1 ? IG4_DATA_STOP : 0; 292448897d3SAndriy Gapon 293448897d3SAndriy Gapon /* Issue request for the first byte (could be last as well). */ 294448897d3SAndriy Gapon reg_write(sc, IG4_REG_DATA_CMD, cmd); 295448897d3SAndriy Gapon 296448897d3SAndriy Gapon for (i = 0; i < len; i++) { 297448897d3SAndriy Gapon /* 298448897d3SAndriy Gapon * Maintain a pipeline by queueing the allowance for the next 299448897d3SAndriy Gapon * read before waiting for the current read. 300448897d3SAndriy Gapon */ 301448897d3SAndriy Gapon cmd = IG4_DATA_COMMAND_RD; 302448897d3SAndriy Gapon if (i < len - 1) { 303448897d3SAndriy Gapon cmd = IG4_DATA_COMMAND_RD; 304448897d3SAndriy Gapon cmd |= stop && i == len - 2 ? IG4_DATA_STOP : 0; 305448897d3SAndriy Gapon reg_write(sc, IG4_REG_DATA_CMD, cmd); 306448897d3SAndriy Gapon } 307448897d3SAndriy Gapon error = wait_status(sc, IG4_STATUS_RX_NOTEMPTY); 308448897d3SAndriy Gapon if (error) 309448897d3SAndriy Gapon break; 310eca74de0SVladimir Kondratyev buf[i] = (uint8_t)reg_read(sc, IG4_REG_DATA_CMD); 311448897d3SAndriy Gapon } 312448897d3SAndriy Gapon 313448897d3SAndriy Gapon (void)reg_read(sc, IG4_REG_TX_ABRT_SOURCE); 314448897d3SAndriy Gapon return (error); 315448897d3SAndriy Gapon } 316448897d3SAndriy Gapon 317448897d3SAndriy Gapon static int 318448897d3SAndriy Gapon ig4iic_write(ig4iic_softc_t *sc, uint8_t *buf, uint16_t len, 319448897d3SAndriy Gapon bool repeated_start, bool stop) 320448897d3SAndriy Gapon { 321448897d3SAndriy Gapon uint32_t cmd; 322448897d3SAndriy Gapon uint16_t i; 323448897d3SAndriy Gapon int error; 324448897d3SAndriy Gapon 325448897d3SAndriy Gapon if (len == 0) 326448897d3SAndriy Gapon return (0); 327448897d3SAndriy Gapon 328448897d3SAndriy Gapon cmd = repeated_start ? IG4_DATA_RESTART : 0; 329448897d3SAndriy Gapon for (i = 0; i < len; i++) { 330448897d3SAndriy Gapon error = wait_status(sc, IG4_STATUS_TX_NOTFULL); 331448897d3SAndriy Gapon if (error) 332448897d3SAndriy Gapon break; 333448897d3SAndriy Gapon cmd |= buf[i]; 334448897d3SAndriy Gapon cmd |= stop && i == len - 1 ? IG4_DATA_STOP : 0; 335448897d3SAndriy Gapon reg_write(sc, IG4_REG_DATA_CMD, cmd); 336448897d3SAndriy Gapon cmd = 0; 337448897d3SAndriy Gapon } 338448897d3SAndriy Gapon 339448897d3SAndriy Gapon (void)reg_read(sc, IG4_REG_TX_ABRT_SOURCE); 340448897d3SAndriy Gapon return (error); 341448897d3SAndriy Gapon } 342448897d3SAndriy Gapon 343448897d3SAndriy Gapon int 344448897d3SAndriy Gapon ig4iic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 345448897d3SAndriy Gapon { 346448897d3SAndriy Gapon ig4iic_softc_t *sc = device_get_softc(dev); 347448897d3SAndriy Gapon const char *reason = NULL; 348448897d3SAndriy Gapon uint32_t i; 349448897d3SAndriy Gapon int error; 350448897d3SAndriy Gapon int unit; 351448897d3SAndriy Gapon bool rpstart; 352448897d3SAndriy Gapon bool stop; 353448897d3SAndriy Gapon 354448897d3SAndriy Gapon /* 355448897d3SAndriy Gapon * The hardware interface imposes limits on allowed I2C messages. 356448897d3SAndriy Gapon * It is not possible to explicitly send a start or stop. 357448897d3SAndriy Gapon * They are automatically sent (or not sent, depending on the 358448897d3SAndriy Gapon * configuration) when a data byte is transferred. 359448897d3SAndriy Gapon * For this reason it's impossible to send a message with no data 360448897d3SAndriy Gapon * at all (like an SMBus quick message). 361448897d3SAndriy Gapon * The start condition is automatically generated after the stop 362448897d3SAndriy Gapon * condition, so it's impossible to not have a start after a stop. 363448897d3SAndriy Gapon * The repeated start condition is automatically sent if a change 364448897d3SAndriy Gapon * of the transfer direction happens, so it's impossible to have 365448897d3SAndriy Gapon * a change of direction without a (repeated) start. 366448897d3SAndriy Gapon * The repeated start can be forced even without the change of 367448897d3SAndriy Gapon * direction. 368448897d3SAndriy Gapon * Changing the target slave address requires resetting the hardware 369448897d3SAndriy Gapon * state, so it's impossible to do that without the stop followed 370448897d3SAndriy Gapon * by the start. 371448897d3SAndriy Gapon */ 372448897d3SAndriy Gapon for (i = 0; i < nmsgs; i++) { 373448897d3SAndriy Gapon #if 0 374448897d3SAndriy Gapon if (i == 0 && (msgs[i].flags & IIC_M_NOSTART) != 0) { 375448897d3SAndriy Gapon reason = "first message without start"; 376448897d3SAndriy Gapon break; 377448897d3SAndriy Gapon } 378448897d3SAndriy Gapon if (i == nmsgs - 1 && (msgs[i].flags & IIC_M_NOSTOP) != 0) { 379448897d3SAndriy Gapon reason = "last message without stop"; 380448897d3SAndriy Gapon break; 381448897d3SAndriy Gapon } 382448897d3SAndriy Gapon #endif 383448897d3SAndriy Gapon if (msgs[i].len == 0) { 384448897d3SAndriy Gapon reason = "message with no data"; 385448897d3SAndriy Gapon break; 386448897d3SAndriy Gapon } 387448897d3SAndriy Gapon if (i > 0) { 388448897d3SAndriy Gapon if ((msgs[i].flags & IIC_M_NOSTART) != 0 && 389448897d3SAndriy Gapon (msgs[i - 1].flags & IIC_M_NOSTOP) == 0) { 390448897d3SAndriy Gapon reason = "stop not followed by start"; 391448897d3SAndriy Gapon break; 392448897d3SAndriy Gapon } 393448897d3SAndriy Gapon if ((msgs[i - 1].flags & IIC_M_NOSTOP) != 0 && 394448897d3SAndriy Gapon msgs[i].slave != msgs[i - 1].slave) { 395448897d3SAndriy Gapon reason = "change of slave without stop"; 396448897d3SAndriy Gapon break; 397448897d3SAndriy Gapon } 398448897d3SAndriy Gapon if ((msgs[i].flags & IIC_M_NOSTART) != 0 && 399448897d3SAndriy Gapon (msgs[i].flags & IIC_M_RD) != 400448897d3SAndriy Gapon (msgs[i - 1].flags & IIC_M_RD)) { 401448897d3SAndriy Gapon reason = "change of direction without repeated" 402448897d3SAndriy Gapon " start"; 403448897d3SAndriy Gapon break; 404448897d3SAndriy Gapon } 405448897d3SAndriy Gapon } 406448897d3SAndriy Gapon } 407448897d3SAndriy Gapon if (reason != NULL) { 408448897d3SAndriy Gapon if (bootverbose) 409448897d3SAndriy Gapon device_printf(dev, "%s\n", reason); 410448897d3SAndriy Gapon return (IIC_ENOTSUPP); 411448897d3SAndriy Gapon } 412448897d3SAndriy Gapon 413448897d3SAndriy Gapon sx_xlock(&sc->call_lock); 414448897d3SAndriy Gapon 415448897d3SAndriy Gapon /* Debugging - dump registers. */ 416448897d3SAndriy Gapon if (ig4_dump) { 417448897d3SAndriy Gapon unit = device_get_unit(dev); 418448897d3SAndriy Gapon if (ig4_dump & (1 << unit)) { 419448897d3SAndriy Gapon ig4_dump &= ~(1 << unit); 420448897d3SAndriy Gapon ig4iic_dump(sc); 421448897d3SAndriy Gapon } 422448897d3SAndriy Gapon } 423448897d3SAndriy Gapon 424448897d3SAndriy Gapon /* 425448897d3SAndriy Gapon * Clear any previous abort condition that may have been holding 426448897d3SAndriy Gapon * the txfifo in reset. 427448897d3SAndriy Gapon */ 428448897d3SAndriy Gapon reg_read(sc, IG4_REG_CLR_TX_ABORT); 429448897d3SAndriy Gapon 430448897d3SAndriy Gapon rpstart = false; 431448897d3SAndriy Gapon error = 0; 432448897d3SAndriy Gapon for (i = 0; i < nmsgs; i++) { 433448897d3SAndriy Gapon if ((msgs[i].flags & IIC_M_NOSTART) == 0) { 434448897d3SAndriy Gapon error = ig4iic_xfer_start(sc, msgs[i].slave); 435448897d3SAndriy Gapon } else { 436448897d3SAndriy Gapon if (!sc->slave_valid || 437448897d3SAndriy Gapon (msgs[i].slave >> 1) != sc->last_slave) { 438448897d3SAndriy Gapon device_printf(dev, "start condition suppressed" 439448897d3SAndriy Gapon "but slave address is not set up"); 440448897d3SAndriy Gapon error = EINVAL; 441448897d3SAndriy Gapon break; 442448897d3SAndriy Gapon } 443448897d3SAndriy Gapon rpstart = false; 444448897d3SAndriy Gapon } 445448897d3SAndriy Gapon if (error != 0) 446448897d3SAndriy Gapon break; 447448897d3SAndriy Gapon 448448897d3SAndriy Gapon stop = (msgs[i].flags & IIC_M_NOSTOP) == 0; 449448897d3SAndriy Gapon if (msgs[i].flags & IIC_M_RD) 450448897d3SAndriy Gapon error = ig4iic_read(sc, msgs[i].buf, msgs[i].len, 451448897d3SAndriy Gapon rpstart, stop); 452448897d3SAndriy Gapon else 453448897d3SAndriy Gapon error = ig4iic_write(sc, msgs[i].buf, msgs[i].len, 454448897d3SAndriy Gapon rpstart, stop); 455448897d3SAndriy Gapon if (error != 0) 456448897d3SAndriy Gapon break; 457448897d3SAndriy Gapon 458448897d3SAndriy Gapon rpstart = !stop; 459448897d3SAndriy Gapon } 460448897d3SAndriy Gapon 461448897d3SAndriy Gapon sx_unlock(&sc->call_lock); 462448897d3SAndriy Gapon return (error); 463448897d3SAndriy Gapon } 464448897d3SAndriy Gapon 465448897d3SAndriy Gapon int 466448897d3SAndriy Gapon ig4iic_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 467448897d3SAndriy Gapon { 468448897d3SAndriy Gapon ig4iic_softc_t *sc = device_get_softc(dev); 469448897d3SAndriy Gapon 470448897d3SAndriy Gapon sx_xlock(&sc->call_lock); 471448897d3SAndriy Gapon 472448897d3SAndriy Gapon /* TODO handle speed configuration? */ 473448897d3SAndriy Gapon if (oldaddr != NULL) 474448897d3SAndriy Gapon *oldaddr = sc->last_slave << 1; 475e3d25549SAndriy Gapon set_slave_addr(sc, addr >> 1); 476448897d3SAndriy Gapon if (addr == IIC_UNKNOWN) 477448897d3SAndriy Gapon sc->slave_valid = false; 478448897d3SAndriy Gapon 479448897d3SAndriy Gapon sx_unlock(&sc->call_lock); 480448897d3SAndriy Gapon return (0); 481448897d3SAndriy Gapon } 482448897d3SAndriy Gapon 483448897d3SAndriy Gapon /* 48471d51719SMichael Gmelin * Called from ig4iic_pci_attach/detach() 48571d51719SMichael Gmelin */ 48671d51719SMichael Gmelin int 48771d51719SMichael Gmelin ig4iic_attach(ig4iic_softc_t *sc) 48871d51719SMichael Gmelin { 48971d51719SMichael Gmelin int error; 49071d51719SMichael Gmelin uint32_t v; 49171d51719SMichael Gmelin 4925c5bcb1dSOleksandr Tymoshenko mtx_init(&sc->io_lock, "IG4 I/O lock", NULL, MTX_DEF); 4935c5bcb1dSOleksandr Tymoshenko sx_init(&sc->call_lock, "IG4 call lock"); 4945c5bcb1dSOleksandr Tymoshenko 495b16d03adSOleksandr Tymoshenko v = reg_read(sc, IG4_REG_DEVIDLE_CTRL); 496b16d03adSOleksandr Tymoshenko if (sc->version == IG4_SKYLAKE && (v & IG4_RESTORE_REQUIRED) ) { 497b16d03adSOleksandr Tymoshenko reg_write(sc, IG4_REG_DEVIDLE_CTRL, IG4_DEVICE_IDLE | IG4_RESTORE_REQUIRED); 498b16d03adSOleksandr Tymoshenko reg_write(sc, IG4_REG_DEVIDLE_CTRL, 0); 499b16d03adSOleksandr Tymoshenko 500b16d03adSOleksandr Tymoshenko reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL); 501b16d03adSOleksandr Tymoshenko reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL); 502b16d03adSOleksandr Tymoshenko DELAY(1000); 503b16d03adSOleksandr Tymoshenko } 504b16d03adSOleksandr Tymoshenko 505b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_ATOM) 50671d51719SMichael Gmelin v = reg_read(sc, IG4_REG_COMP_TYPE); 507b3e8ee5dSOleksandr Tymoshenko 508b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) { 50971d51719SMichael Gmelin v = reg_read(sc, IG4_REG_COMP_PARAM1); 51071d51719SMichael Gmelin v = reg_read(sc, IG4_REG_GENERAL); 511b3e8ee5dSOleksandr Tymoshenko /* 512b3e8ee5dSOleksandr Tymoshenko * The content of IG4_REG_GENERAL is different for each 513b3e8ee5dSOleksandr Tymoshenko * controller version. 514b3e8ee5dSOleksandr Tymoshenko */ 515b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL && 516b3e8ee5dSOleksandr Tymoshenko (v & IG4_GENERAL_SWMODE) == 0) { 51771d51719SMichael Gmelin v |= IG4_GENERAL_SWMODE; 51871d51719SMichael Gmelin reg_write(sc, IG4_REG_GENERAL, v); 51971d51719SMichael Gmelin v = reg_read(sc, IG4_REG_GENERAL); 52071d51719SMichael Gmelin } 521b3e8ee5dSOleksandr Tymoshenko } 52271d51719SMichael Gmelin 523b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL) { 52471d51719SMichael Gmelin v = reg_read(sc, IG4_REG_SW_LTR_VALUE); 52571d51719SMichael Gmelin v = reg_read(sc, IG4_REG_AUTO_LTR_VALUE); 526b3e8ee5dSOleksandr Tymoshenko } else if (sc->version == IG4_SKYLAKE) { 527b3e8ee5dSOleksandr Tymoshenko v = reg_read(sc, IG4_REG_ACTIVE_LTR_VALUE); 528b3e8ee5dSOleksandr Tymoshenko v = reg_read(sc, IG4_REG_IDLE_LTR_VALUE); 529b3e8ee5dSOleksandr Tymoshenko } 53071d51719SMichael Gmelin 531b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) { 53271d51719SMichael Gmelin v = reg_read(sc, IG4_REG_COMP_VER); 5335747fe4fSOleksandr Tymoshenko if (v < IG4_COMP_MIN_VER) { 53471d51719SMichael Gmelin error = ENXIO; 53571d51719SMichael Gmelin goto done; 53671d51719SMichael Gmelin } 537b3e8ee5dSOleksandr Tymoshenko } 538d117e363SVladimir Kondratyev 539d117e363SVladimir Kondratyev if (set_controller(sc, 0)) { 540d117e363SVladimir Kondratyev device_printf(sc->dev, "controller error during attach-1\n"); 541d117e363SVladimir Kondratyev error = ENXIO; 542d117e363SVladimir Kondratyev goto done; 543d117e363SVladimir Kondratyev } 544d117e363SVladimir Kondratyev 54571d51719SMichael Gmelin v = reg_read(sc, IG4_REG_SS_SCL_HCNT); 54671d51719SMichael Gmelin v = reg_read(sc, IG4_REG_SS_SCL_LCNT); 54771d51719SMichael Gmelin v = reg_read(sc, IG4_REG_FS_SCL_HCNT); 54871d51719SMichael Gmelin v = reg_read(sc, IG4_REG_FS_SCL_LCNT); 54971d51719SMichael Gmelin v = reg_read(sc, IG4_REG_SDA_HOLD); 55071d51719SMichael Gmelin 55171d51719SMichael Gmelin v = reg_read(sc, IG4_REG_SS_SCL_HCNT); 55271d51719SMichael Gmelin reg_write(sc, IG4_REG_FS_SCL_HCNT, v); 55371d51719SMichael Gmelin v = reg_read(sc, IG4_REG_SS_SCL_LCNT); 55471d51719SMichael Gmelin reg_write(sc, IG4_REG_FS_SCL_LCNT, v); 55571d51719SMichael Gmelin 55621e459c6SVladimir Kondratyev reg_read(sc, IG4_REG_CLR_INTR); 55721e459c6SVladimir Kondratyev reg_write(sc, IG4_REG_INTR_MASK, 0); 55821e459c6SVladimir Kondratyev sc->intr_mask = 0; 55921e459c6SVladimir Kondratyev 56071d51719SMichael Gmelin /* 56171d51719SMichael Gmelin * Program based on a 25000 Hz clock. This is a bit of a 56271d51719SMichael Gmelin * hack (obviously). The defaults are 400 and 470 for standard 56371d51719SMichael Gmelin * and 60 and 130 for fast. The defaults for standard fail 56471d51719SMichael Gmelin * utterly (presumably cause an abort) because the clock time 56571d51719SMichael Gmelin * is ~18.8ms by default. This brings it down to ~4ms (for now). 56671d51719SMichael Gmelin */ 56771d51719SMichael Gmelin reg_write(sc, IG4_REG_SS_SCL_HCNT, 100); 56871d51719SMichael Gmelin reg_write(sc, IG4_REG_SS_SCL_LCNT, 125); 56971d51719SMichael Gmelin reg_write(sc, IG4_REG_FS_SCL_HCNT, 100); 57071d51719SMichael Gmelin reg_write(sc, IG4_REG_FS_SCL_LCNT, 125); 5713ca6000fSVladimir Kondratyev if (sc->version == IG4_SKYLAKE) 5723ca6000fSVladimir Kondratyev reg_write(sc, IG4_REG_SDA_HOLD, 28); 57371d51719SMichael Gmelin 57471d51719SMichael Gmelin /* 57571d51719SMichael Gmelin * Use a threshold of 1 so we get interrupted on each character, 57671d51719SMichael Gmelin * allowing us to use mtx_sleep() in our poll code. Not perfect 57771d51719SMichael Gmelin * but this is better than using DELAY() for receiving data. 5784cd6abddSMichael Gmelin * 5794cd6abddSMichael Gmelin * See ig4_var.h for details on interrupt handler synchronization. 58071d51719SMichael Gmelin */ 581811ff4ddSVladimir Kondratyev reg_write(sc, IG4_REG_RX_TL, 0); 58271d51719SMichael Gmelin 58371d51719SMichael Gmelin reg_write(sc, IG4_REG_CTL, 58471d51719SMichael Gmelin IG4_CTL_MASTER | 58571d51719SMichael Gmelin IG4_CTL_SLAVE_DISABLE | 58671d51719SMichael Gmelin IG4_CTL_RESTARTEN | 58771d51719SMichael Gmelin IG4_CTL_SPEED_STD); 58871d51719SMichael Gmelin 589448897d3SAndriy Gapon sc->iicbus = device_add_child(sc->dev, "iicbus", -1); 590448897d3SAndriy Gapon if (sc->iicbus == NULL) { 591448897d3SAndriy Gapon device_printf(sc->dev, "iicbus driver not found\n"); 59271d51719SMichael Gmelin error = ENXIO; 59371d51719SMichael Gmelin goto done; 59471d51719SMichael Gmelin } 59571d51719SMichael Gmelin 59671d51719SMichael Gmelin #if 0 59771d51719SMichael Gmelin /* 59871d51719SMichael Gmelin * Don't do this, it blows up the PCI config 59971d51719SMichael Gmelin */ 600b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) { 601b3e8ee5dSOleksandr Tymoshenko reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_ASSERT_HSW); 602b3e8ee5dSOleksandr Tymoshenko reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_DEASSERT_HSW); 603b3e8ee5dSOleksandr Tymoshenko } else if (sc->version = IG4_SKYLAKE) { 604b3e8ee5dSOleksandr Tymoshenko reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL); 605b3e8ee5dSOleksandr Tymoshenko reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL); 606b3e8ee5dSOleksandr Tymoshenko } 60771d51719SMichael Gmelin #endif 60871d51719SMichael Gmelin 609bf9c3c58SVladimir Kondratyev if (set_controller(sc, IG4_I2C_ENABLE)) { 61071d51719SMichael Gmelin device_printf(sc->dev, "controller error during attach-2\n"); 611bf9c3c58SVladimir Kondratyev error = ENXIO; 612bf9c3c58SVladimir Kondratyev goto done; 613bf9c3c58SVladimir Kondratyev } 614edcf6a9fSVladimir Kondratyev if (set_controller(sc, 0)) { 615edcf6a9fSVladimir Kondratyev device_printf(sc->dev, "controller error during attach-3\n"); 616edcf6a9fSVladimir Kondratyev error = ENXIO; 617edcf6a9fSVladimir Kondratyev goto done; 618edcf6a9fSVladimir Kondratyev } 61971d51719SMichael Gmelin error = bus_setup_intr(sc->dev, sc->intr_res, INTR_TYPE_MISC | INTR_MPSAFE, 62071d51719SMichael Gmelin NULL, ig4iic_intr, sc, &sc->intr_handle); 62171d51719SMichael Gmelin if (error) { 62271d51719SMichael Gmelin device_printf(sc->dev, 62371d51719SMichael Gmelin "Unable to setup irq: error %d\n", error); 62471d51719SMichael Gmelin } 62571d51719SMichael Gmelin 62671d51719SMichael Gmelin sc->enum_hook.ich_func = ig4iic_start; 62771d51719SMichael Gmelin sc->enum_hook.ich_arg = sc->dev; 62871d51719SMichael Gmelin 6290ba5622dSMichael Gmelin /* 6300ba5622dSMichael Gmelin * We have to wait until interrupts are enabled. I2C read and write 63171d51719SMichael Gmelin * only works if the interrupts are available. 63271d51719SMichael Gmelin */ 63371d51719SMichael Gmelin if (config_intrhook_establish(&sc->enum_hook) != 0) 63471d51719SMichael Gmelin error = ENOMEM; 63571d51719SMichael Gmelin else 63671d51719SMichael Gmelin error = 0; 63771d51719SMichael Gmelin 63871d51719SMichael Gmelin done: 63971d51719SMichael Gmelin return (error); 64071d51719SMichael Gmelin } 64171d51719SMichael Gmelin 64271d51719SMichael Gmelin void 64371d51719SMichael Gmelin ig4iic_start(void *xdev) 64471d51719SMichael Gmelin { 64571d51719SMichael Gmelin int error; 64671d51719SMichael Gmelin ig4iic_softc_t *sc; 64771d51719SMichael Gmelin device_t dev = (device_t)xdev; 64871d51719SMichael Gmelin 64971d51719SMichael Gmelin sc = device_get_softc(dev); 65071d51719SMichael Gmelin 65171d51719SMichael Gmelin config_intrhook_disestablish(&sc->enum_hook); 65271d51719SMichael Gmelin 65371d51719SMichael Gmelin error = bus_generic_attach(sc->dev); 65471d51719SMichael Gmelin if (error) { 65571d51719SMichael Gmelin device_printf(sc->dev, 65671d51719SMichael Gmelin "failed to attach child: error %d\n", error); 65771d51719SMichael Gmelin } 65871d51719SMichael Gmelin } 65971d51719SMichael Gmelin 66071d51719SMichael Gmelin int 66171d51719SMichael Gmelin ig4iic_detach(ig4iic_softc_t *sc) 66271d51719SMichael Gmelin { 66371d51719SMichael Gmelin int error; 66471d51719SMichael Gmelin 66571d51719SMichael Gmelin if (device_is_attached(sc->dev)) { 66671d51719SMichael Gmelin error = bus_generic_detach(sc->dev); 66771d51719SMichael Gmelin if (error) 66871d51719SMichael Gmelin return (error); 66971d51719SMichael Gmelin } 670448897d3SAndriy Gapon if (sc->iicbus) 671448897d3SAndriy Gapon device_delete_child(sc->dev, sc->iicbus); 67271d51719SMichael Gmelin if (sc->intr_handle) 67371d51719SMichael Gmelin bus_teardown_intr(sc->dev, sc->intr_res, sc->intr_handle); 67471d51719SMichael Gmelin 6754cd6abddSMichael Gmelin sx_xlock(&sc->call_lock); 67671d51719SMichael Gmelin 677448897d3SAndriy Gapon sc->iicbus = NULL; 67871d51719SMichael Gmelin sc->intr_handle = NULL; 67971d51719SMichael Gmelin reg_write(sc, IG4_REG_INTR_MASK, 0); 68071d51719SMichael Gmelin set_controller(sc, 0); 68171d51719SMichael Gmelin 6824cd6abddSMichael Gmelin sx_xunlock(&sc->call_lock); 6835c5bcb1dSOleksandr Tymoshenko 6845c5bcb1dSOleksandr Tymoshenko mtx_destroy(&sc->io_lock); 6855c5bcb1dSOleksandr Tymoshenko sx_destroy(&sc->call_lock); 6865c5bcb1dSOleksandr Tymoshenko 68771d51719SMichael Gmelin return (0); 68871d51719SMichael Gmelin } 68971d51719SMichael Gmelin 69071d51719SMichael Gmelin /* 6914cd6abddSMichael Gmelin * Interrupt Operation, see ig4_var.h for locking semantics. 69271d51719SMichael Gmelin */ 69371d51719SMichael Gmelin static void 69471d51719SMichael Gmelin ig4iic_intr(void *cookie) 69571d51719SMichael Gmelin { 69671d51719SMichael Gmelin ig4iic_softc_t *sc = cookie; 69771d51719SMichael Gmelin 6984cd6abddSMichael Gmelin mtx_lock(&sc->io_lock); 6990a6b1b56SVladimir Kondratyev /* Ignore stray interrupts */ 7000a6b1b56SVladimir Kondratyev if (sc->intr_mask != 0 && reg_read(sc, IG4_REG_INTR_STAT) != 0) { 70121e459c6SVladimir Kondratyev set_intr_mask(sc, 0); 7020ba5622dSMichael Gmelin reg_read(sc, IG4_REG_CLR_INTR); 70371d51719SMichael Gmelin wakeup(sc); 7040a6b1b56SVladimir Kondratyev } 7054cd6abddSMichael Gmelin mtx_unlock(&sc->io_lock); 70671d51719SMichael Gmelin } 70771d51719SMichael Gmelin 70871d51719SMichael Gmelin #define REGDUMP(sc, reg) \ 70971d51719SMichael Gmelin device_printf(sc->dev, " %-23s %08x\n", #reg, reg_read(sc, reg)) 71071d51719SMichael Gmelin 71171d51719SMichael Gmelin static void 71271d51719SMichael Gmelin ig4iic_dump(ig4iic_softc_t *sc) 71371d51719SMichael Gmelin { 71471d51719SMichael Gmelin device_printf(sc->dev, "ig4iic register dump:\n"); 71571d51719SMichael Gmelin REGDUMP(sc, IG4_REG_CTL); 71671d51719SMichael Gmelin REGDUMP(sc, IG4_REG_TAR_ADD); 71771d51719SMichael Gmelin REGDUMP(sc, IG4_REG_SS_SCL_HCNT); 71871d51719SMichael Gmelin REGDUMP(sc, IG4_REG_SS_SCL_LCNT); 71971d51719SMichael Gmelin REGDUMP(sc, IG4_REG_FS_SCL_HCNT); 72071d51719SMichael Gmelin REGDUMP(sc, IG4_REG_FS_SCL_LCNT); 72171d51719SMichael Gmelin REGDUMP(sc, IG4_REG_INTR_STAT); 72271d51719SMichael Gmelin REGDUMP(sc, IG4_REG_INTR_MASK); 72371d51719SMichael Gmelin REGDUMP(sc, IG4_REG_RAW_INTR_STAT); 72471d51719SMichael Gmelin REGDUMP(sc, IG4_REG_RX_TL); 72571d51719SMichael Gmelin REGDUMP(sc, IG4_REG_TX_TL); 72671d51719SMichael Gmelin REGDUMP(sc, IG4_REG_I2C_EN); 72771d51719SMichael Gmelin REGDUMP(sc, IG4_REG_I2C_STA); 72871d51719SMichael Gmelin REGDUMP(sc, IG4_REG_TXFLR); 72971d51719SMichael Gmelin REGDUMP(sc, IG4_REG_RXFLR); 73071d51719SMichael Gmelin REGDUMP(sc, IG4_REG_SDA_HOLD); 73171d51719SMichael Gmelin REGDUMP(sc, IG4_REG_TX_ABRT_SOURCE); 73271d51719SMichael Gmelin REGDUMP(sc, IG4_REG_SLV_DATA_NACK); 73371d51719SMichael Gmelin REGDUMP(sc, IG4_REG_DMA_CTRL); 73471d51719SMichael Gmelin REGDUMP(sc, IG4_REG_DMA_TDLR); 73571d51719SMichael Gmelin REGDUMP(sc, IG4_REG_DMA_RDLR); 73671d51719SMichael Gmelin REGDUMP(sc, IG4_REG_SDA_SETUP); 73771d51719SMichael Gmelin REGDUMP(sc, IG4_REG_ENABLE_STATUS); 738b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) { 73971d51719SMichael Gmelin REGDUMP(sc, IG4_REG_COMP_PARAM1); 74071d51719SMichael Gmelin REGDUMP(sc, IG4_REG_COMP_VER); 741b3e8ee5dSOleksandr Tymoshenko } 742b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_ATOM) { 74371d51719SMichael Gmelin REGDUMP(sc, IG4_REG_COMP_TYPE); 74471d51719SMichael Gmelin REGDUMP(sc, IG4_REG_CLK_PARMS); 745b3e8ee5dSOleksandr Tymoshenko } 746b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) { 747b3e8ee5dSOleksandr Tymoshenko REGDUMP(sc, IG4_REG_RESETS_HSW); 74871d51719SMichael Gmelin REGDUMP(sc, IG4_REG_GENERAL); 749b3e8ee5dSOleksandr Tymoshenko } else if (sc->version == IG4_SKYLAKE) { 750b3e8ee5dSOleksandr Tymoshenko REGDUMP(sc, IG4_REG_RESETS_SKL); 751b3e8ee5dSOleksandr Tymoshenko } 752b3e8ee5dSOleksandr Tymoshenko if (sc->version == IG4_HASWELL) { 75371d51719SMichael Gmelin REGDUMP(sc, IG4_REG_SW_LTR_VALUE); 75471d51719SMichael Gmelin REGDUMP(sc, IG4_REG_AUTO_LTR_VALUE); 755b3e8ee5dSOleksandr Tymoshenko } else if (sc->version == IG4_SKYLAKE) { 756b3e8ee5dSOleksandr Tymoshenko REGDUMP(sc, IG4_REG_ACTIVE_LTR_VALUE); 757b3e8ee5dSOleksandr Tymoshenko REGDUMP(sc, IG4_REG_IDLE_LTR_VALUE); 758b3e8ee5dSOleksandr Tymoshenko } 75971d51719SMichael Gmelin } 76071d51719SMichael Gmelin #undef REGDUMP 76171d51719SMichael Gmelin 762984ed3e4SVladimir Kondratyev devclass_t ig4iic_devclass; 763984ed3e4SVladimir Kondratyev 764984ed3e4SVladimir Kondratyev DRIVER_MODULE(iicbus, ig4iic, iicbus_driver, iicbus_devclass, NULL, NULL); 765984ed3e4SVladimir Kondratyev MODULE_DEPEND(ig4iic, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 766984ed3e4SVladimir Kondratyev MODULE_VERSION(ig4iic, 1); 767