1a9cade51SNathan Whitehorn /*- 2a9cade51SNathan Whitehorn * Copyright (c) 2001 Tsubai Masanari. All rights reserved. 3a9cade51SNathan Whitehorn * 4a9cade51SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 5a9cade51SNathan Whitehorn * modification, are permitted provided that the following conditions 6a9cade51SNathan Whitehorn * are met: 7a9cade51SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 8a9cade51SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 9a9cade51SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 10a9cade51SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 11a9cade51SNathan Whitehorn * documentation and/or other materials provided with the distribution. 12a9cade51SNathan Whitehorn * 3. The name of the author may not be used to endorse or promote products 13a9cade51SNathan Whitehorn * derived from this software without specific prior written permission. 14a9cade51SNathan Whitehorn * 15a9cade51SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16a9cade51SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17a9cade51SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18a9cade51SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19a9cade51SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20a9cade51SNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21a9cade51SNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22a9cade51SNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23a9cade51SNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24a9cade51SNathan Whitehorn * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25a9cade51SNathan Whitehorn * 26a9cade51SNathan Whitehorn * $FreeBSD$ 27a9cade51SNathan Whitehorn * NetBSD: ki2c.c,v 1.11 2007/12/06 17:00:33 ad Exp 28a9cade51SNathan Whitehorn * Id: ki2c.c,v 1.7 2002/10/05 09:56:05 tsubai Exp 29a9cade51SNathan Whitehorn */ 30a9cade51SNathan Whitehorn 31a9cade51SNathan Whitehorn /* 32a9cade51SNathan Whitehorn * Support routines for the Keywest I2C controller. 33a9cade51SNathan Whitehorn */ 34a9cade51SNathan Whitehorn 35a9cade51SNathan Whitehorn #include <sys/param.h> 36a9cade51SNathan Whitehorn #include <sys/systm.h> 37a9cade51SNathan Whitehorn #include <sys/kernel.h> 38a9cade51SNathan Whitehorn #include <sys/module.h> 39a9cade51SNathan Whitehorn #include <sys/bus.h> 40a9cade51SNathan Whitehorn #include <sys/lock.h> 41a9cade51SNathan Whitehorn #include <sys/mutex.h> 42a9cade51SNathan Whitehorn #include <machine/resource.h> 43a9cade51SNathan Whitehorn #include <machine/bus.h> 44a9cade51SNathan Whitehorn #include <sys/rman.h> 45a9cade51SNathan Whitehorn 46a9cade51SNathan Whitehorn #include <dev/iicbus/iicbus.h> 47a9cade51SNathan Whitehorn #include <dev/iicbus/iiconf.h> 48a9cade51SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 49a9cade51SNathan Whitehorn #include "iicbus_if.h" 50a9cade51SNathan Whitehorn 51a9cade51SNathan Whitehorn /* Keywest I2C Register offsets */ 52a9cade51SNathan Whitehorn #define MODE 0 53a9cade51SNathan Whitehorn #define CONTROL 1 54a9cade51SNathan Whitehorn #define STATUS 2 55a9cade51SNathan Whitehorn #define ISR 3 56a9cade51SNathan Whitehorn #define IER 4 57a9cade51SNathan Whitehorn #define ADDR 5 58a9cade51SNathan Whitehorn #define SUBADDR 6 59a9cade51SNathan Whitehorn #define DATA 7 60c8812077SNathan Whitehorn #define REV 8 61a9cade51SNathan Whitehorn 62a9cade51SNathan Whitehorn /* MODE */ 63a9cade51SNathan Whitehorn #define I2C_SPEED 0x03 /* Speed mask */ 64a9cade51SNathan Whitehorn #define I2C_100kHz 0x00 65a9cade51SNathan Whitehorn #define I2C_50kHz 0x01 66a9cade51SNathan Whitehorn #define I2C_25kHz 0x02 67a9cade51SNathan Whitehorn #define I2C_MODE 0x0c /* Mode mask */ 68a9cade51SNathan Whitehorn #define I2C_DUMBMODE 0x00 /* Dumb mode */ 69a9cade51SNathan Whitehorn #define I2C_STDMODE 0x04 /* Standard mode */ 70a9cade51SNathan Whitehorn #define I2C_STDSUBMODE 0x08 /* Standard mode + sub address */ 71a9cade51SNathan Whitehorn #define I2C_COMBMODE 0x0c /* Combined mode */ 72a9cade51SNathan Whitehorn #define I2C_PORT 0xf0 /* Port mask */ 73a9cade51SNathan Whitehorn 74a9cade51SNathan Whitehorn /* CONTROL */ 75a9cade51SNathan Whitehorn #define I2C_CT_AAK 0x01 /* Send AAK */ 76a9cade51SNathan Whitehorn #define I2C_CT_ADDR 0x02 /* Send address(es) */ 77a9cade51SNathan Whitehorn #define I2C_CT_STOP 0x04 /* Send STOP */ 78a9cade51SNathan Whitehorn #define I2C_CT_START 0x08 /* Send START */ 79a9cade51SNathan Whitehorn 80a9cade51SNathan Whitehorn /* STATUS */ 81a9cade51SNathan Whitehorn #define I2C_ST_BUSY 0x01 /* Busy */ 82a9cade51SNathan Whitehorn #define I2C_ST_LASTAAK 0x02 /* Last AAK */ 83a9cade51SNathan Whitehorn #define I2C_ST_LASTRW 0x04 /* Last R/W */ 84a9cade51SNathan Whitehorn #define I2C_ST_SDA 0x08 /* SDA */ 85a9cade51SNathan Whitehorn #define I2C_ST_SCL 0x10 /* SCL */ 86a9cade51SNathan Whitehorn 87a9cade51SNathan Whitehorn /* ISR/IER */ 88a9cade51SNathan Whitehorn #define I2C_INT_DATA 0x01 /* Data byte sent/received */ 89a9cade51SNathan Whitehorn #define I2C_INT_ADDR 0x02 /* Address sent */ 90a9cade51SNathan Whitehorn #define I2C_INT_STOP 0x04 /* STOP condition sent */ 91a9cade51SNathan Whitehorn #define I2C_INT_START 0x08 /* START condition sent */ 92a9cade51SNathan Whitehorn 93a9cade51SNathan Whitehorn /* I2C flags */ 94a9cade51SNathan Whitehorn #define I2C_BUSY 0x01 95a9cade51SNathan Whitehorn #define I2C_READING 0x02 96a9cade51SNathan Whitehorn #define I2C_ERROR 0x04 97a9cade51SNathan Whitehorn #define I2C_SELECTED 0x08 98a9cade51SNathan Whitehorn 99a9cade51SNathan Whitehorn struct kiic_softc { 100a9cade51SNathan Whitehorn device_t sc_dev; 101a9cade51SNathan Whitehorn phandle_t sc_node; 102a9cade51SNathan Whitehorn struct mtx sc_mutex; 103a9cade51SNathan Whitehorn struct resource *sc_reg; 104a9cade51SNathan Whitehorn int sc_irqrid; 105a9cade51SNathan Whitehorn struct resource *sc_irq; 106a9cade51SNathan Whitehorn void *sc_ih; 107a9cade51SNathan Whitehorn u_int sc_regstep; 108a9cade51SNathan Whitehorn u_int sc_flags; 109a9cade51SNathan Whitehorn u_char *sc_data; 110a9cade51SNathan Whitehorn int sc_resid; 111c933841dSNathan Whitehorn uint16_t sc_i2c_base; 112a9cade51SNathan Whitehorn device_t sc_iicbus; 113a9cade51SNathan Whitehorn }; 114a9cade51SNathan Whitehorn 115a9cade51SNathan Whitehorn static int kiic_probe(device_t dev); 116a9cade51SNathan Whitehorn static int kiic_attach(device_t dev); 117a9cade51SNathan Whitehorn static void kiic_writereg(struct kiic_softc *sc, u_int, u_int); 118a9cade51SNathan Whitehorn static u_int kiic_readreg(struct kiic_softc *, u_int); 119c933841dSNathan Whitehorn static void kiic_setport(struct kiic_softc *, u_int); 120a9cade51SNathan Whitehorn static void kiic_setmode(struct kiic_softc *, u_int); 121a9cade51SNathan Whitehorn static void kiic_setspeed(struct kiic_softc *, u_int); 122a9cade51SNathan Whitehorn static void kiic_intr(void *xsc); 123a9cade51SNathan Whitehorn static int kiic_transfer(device_t dev, struct iic_msg *msgs, 124a9cade51SNathan Whitehorn uint32_t nmsgs); 125a9cade51SNathan Whitehorn static phandle_t kiic_get_node(device_t bus, device_t dev); 126a9cade51SNathan Whitehorn 127a9cade51SNathan Whitehorn static device_method_t kiic_methods[] = { 128a9cade51SNathan Whitehorn /* device interface */ 129a9cade51SNathan Whitehorn DEVMETHOD(device_probe, kiic_probe), 130a9cade51SNathan Whitehorn DEVMETHOD(device_attach, kiic_attach), 131a9cade51SNathan Whitehorn 132a9cade51SNathan Whitehorn /* iicbus interface */ 133a9cade51SNathan Whitehorn DEVMETHOD(iicbus_callback, iicbus_null_callback), 134a9cade51SNathan Whitehorn DEVMETHOD(iicbus_transfer, kiic_transfer), 135a9cade51SNathan Whitehorn 136a9cade51SNathan Whitehorn /* ofw_bus interface */ 137a9cade51SNathan Whitehorn DEVMETHOD(ofw_bus_get_node, kiic_get_node), 138a9cade51SNathan Whitehorn 139a9cade51SNathan Whitehorn { 0, 0 } 140a9cade51SNathan Whitehorn }; 141a9cade51SNathan Whitehorn 142a9cade51SNathan Whitehorn static driver_t kiic_driver = { 143a9cade51SNathan Whitehorn "iichb", 144a9cade51SNathan Whitehorn kiic_methods, 145a9cade51SNathan Whitehorn sizeof(struct kiic_softc) 146a9cade51SNathan Whitehorn }; 147a9cade51SNathan Whitehorn static devclass_t kiic_devclass; 148a9cade51SNathan Whitehorn 149a9cade51SNathan Whitehorn DRIVER_MODULE(kiic, macio, kiic_driver, kiic_devclass, 0, 0); 150c8812077SNathan Whitehorn DRIVER_MODULE(kiic, unin, kiic_driver, kiic_devclass, 0, 0); 151a9cade51SNathan Whitehorn 152a9cade51SNathan Whitehorn static int 153a9cade51SNathan Whitehorn kiic_probe(device_t self) 154a9cade51SNathan Whitehorn { 155a9cade51SNathan Whitehorn const char *name; 156a9cade51SNathan Whitehorn 157a9cade51SNathan Whitehorn name = ofw_bus_get_name(self); 158a9cade51SNathan Whitehorn if (name && strcmp(name, "i2c") == 0) { 159a9cade51SNathan Whitehorn device_set_desc(self, "Keywest I2C controller"); 160a9cade51SNathan Whitehorn return (0); 161a9cade51SNathan Whitehorn } 162a9cade51SNathan Whitehorn 163a9cade51SNathan Whitehorn return (ENXIO); 164a9cade51SNathan Whitehorn } 165a9cade51SNathan Whitehorn 166a9cade51SNathan Whitehorn static int 167a9cade51SNathan Whitehorn kiic_attach(device_t self) 168a9cade51SNathan Whitehorn { 169a9cade51SNathan Whitehorn struct kiic_softc *sc = device_get_softc(self); 170a9cade51SNathan Whitehorn int rid, rate; 171a9cade51SNathan Whitehorn phandle_t node; 172a9cade51SNathan Whitehorn char name[64]; 173a9cade51SNathan Whitehorn 174a9cade51SNathan Whitehorn bzero(sc, sizeof(*sc)); 175a9cade51SNathan Whitehorn sc->sc_dev = self; 176a9cade51SNathan Whitehorn 177a9cade51SNathan Whitehorn node = ofw_bus_get_node(self); 178a9cade51SNathan Whitehorn if (node == 0 || node == -1) { 179a9cade51SNathan Whitehorn return (EINVAL); 180a9cade51SNathan Whitehorn } 181a9cade51SNathan Whitehorn 182a9cade51SNathan Whitehorn rid = 0; 183a9cade51SNathan Whitehorn sc->sc_reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, 184a9cade51SNathan Whitehorn &rid, RF_ACTIVE); 185a9cade51SNathan Whitehorn if (sc->sc_reg == NULL) { 186a9cade51SNathan Whitehorn return (ENOMEM); 187a9cade51SNathan Whitehorn } 188a9cade51SNathan Whitehorn 189*509142e1SNathan Whitehorn if (OF_getencprop(node, "AAPL,i2c-rate", &rate, 4) != 4) { 190a9cade51SNathan Whitehorn device_printf(self, "cannot get i2c-rate\n"); 191a9cade51SNathan Whitehorn return (ENXIO); 192a9cade51SNathan Whitehorn } 193*509142e1SNathan Whitehorn if (OF_getencprop(node, "AAPL,address-step", &sc->sc_regstep, 4) != 4) { 194a9cade51SNathan Whitehorn device_printf(self, "unable to find i2c address step\n"); 195a9cade51SNathan Whitehorn return (ENXIO); 196a9cade51SNathan Whitehorn } 197a9cade51SNathan Whitehorn 198a9cade51SNathan Whitehorn /* 199a9cade51SNathan Whitehorn * Some Keywest I2C devices have their children attached directly 200a9cade51SNathan Whitehorn * underneath them. Some have a single 'iicbus' child with the 201a9cade51SNathan Whitehorn * devices underneath that. Sort this out, and make sure that the 202a9cade51SNathan Whitehorn * OFW I2C layer has the correct node. 203c933841dSNathan Whitehorn * 204c933841dSNathan Whitehorn * Note: the I2C children of the Uninorth bridges have two ports. 205c933841dSNathan Whitehorn * In general, the port is designated in the 9th bit of the I2C 206c933841dSNathan Whitehorn * address. However, for kiic devices with children attached below 207c933841dSNathan Whitehorn * an i2c-bus node, the port is indicated in the 'reg' property 208c933841dSNathan Whitehorn * of the i2c-bus node. 209a9cade51SNathan Whitehorn */ 210a9cade51SNathan Whitehorn 211a9cade51SNathan Whitehorn sc->sc_node = node; 212c933841dSNathan Whitehorn 213c933841dSNathan Whitehorn node = OF_child(node); 214c933841dSNathan Whitehorn if (OF_getprop(node, "name", name, sizeof(name)) > 0) { 215c933841dSNathan Whitehorn if (strcmp(name,"i2c-bus") == 0) { 216c933841dSNathan Whitehorn phandle_t reg; 217c933841dSNathan Whitehorn if (OF_getprop(node, "reg", ®, sizeof(reg)) > 0) 218c933841dSNathan Whitehorn sc->sc_i2c_base = reg << 8; 219c933841dSNathan Whitehorn 220c933841dSNathan Whitehorn sc->sc_node = node; 221c933841dSNathan Whitehorn } 222a9cade51SNathan Whitehorn } 223a9cade51SNathan Whitehorn 224a9cade51SNathan Whitehorn mtx_init(&sc->sc_mutex, "kiic", NULL, MTX_DEF); 225a9cade51SNathan Whitehorn 226a9cade51SNathan Whitehorn sc->sc_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, &sc->sc_irqrid, 227a9cade51SNathan Whitehorn RF_ACTIVE); 228a9cade51SNathan Whitehorn bus_setup_intr(self, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL, 229a9cade51SNathan Whitehorn kiic_intr, sc, &sc->sc_ih); 230a9cade51SNathan Whitehorn 231c933841dSNathan Whitehorn kiic_writereg(sc, ISR, kiic_readreg(sc, ISR)); 232a9cade51SNathan Whitehorn kiic_writereg(sc, STATUS, 0); 233a9cade51SNathan Whitehorn kiic_writereg(sc, IER, 0); 234a9cade51SNathan Whitehorn 235a9cade51SNathan Whitehorn kiic_setmode(sc, I2C_STDMODE); 236a9cade51SNathan Whitehorn kiic_setspeed(sc, I2C_100kHz); /* XXX rate */ 237a9cade51SNathan Whitehorn 238a9cade51SNathan Whitehorn kiic_writereg(sc, IER, I2C_INT_DATA | I2C_INT_ADDR | I2C_INT_STOP); 239a9cade51SNathan Whitehorn 240c8812077SNathan Whitehorn if (bootverbose) 241c8812077SNathan Whitehorn device_printf(self, "Revision: %02X\n", kiic_readreg(sc, REV)); 242c8812077SNathan Whitehorn 243a9cade51SNathan Whitehorn /* Add the IIC bus layer */ 244a9cade51SNathan Whitehorn sc->sc_iicbus = device_add_child(self, "iicbus", -1); 245a9cade51SNathan Whitehorn 246a9cade51SNathan Whitehorn return (bus_generic_attach(self)); 247a9cade51SNathan Whitehorn } 248a9cade51SNathan Whitehorn 249a9cade51SNathan Whitehorn static void 250a9cade51SNathan Whitehorn kiic_writereg(struct kiic_softc *sc, u_int reg, u_int val) 251a9cade51SNathan Whitehorn { 252c8812077SNathan Whitehorn bus_write_4(sc->sc_reg, sc->sc_regstep * reg, val); 25323aa1a1dSAndreas Tobler DELAY(100); /* register access delay */ 254a9cade51SNathan Whitehorn } 255a9cade51SNathan Whitehorn 256a9cade51SNathan Whitehorn static u_int 257a9cade51SNathan Whitehorn kiic_readreg(struct kiic_softc *sc, u_int reg) 258a9cade51SNathan Whitehorn { 259c8812077SNathan Whitehorn return bus_read_4(sc->sc_reg, sc->sc_regstep * reg) & 0xff; 260a9cade51SNathan Whitehorn } 261a9cade51SNathan Whitehorn 262a9cade51SNathan Whitehorn static void 263a9cade51SNathan Whitehorn kiic_setmode(struct kiic_softc *sc, u_int mode) 264a9cade51SNathan Whitehorn { 265a9cade51SNathan Whitehorn u_int x; 266a9cade51SNathan Whitehorn 267a9cade51SNathan Whitehorn KASSERT((mode & ~I2C_MODE) == 0, ("bad mode")); 268a9cade51SNathan Whitehorn x = kiic_readreg(sc, MODE); 269a9cade51SNathan Whitehorn x &= ~I2C_MODE; 270a9cade51SNathan Whitehorn x |= mode; 271a9cade51SNathan Whitehorn kiic_writereg(sc, MODE, x); 272a9cade51SNathan Whitehorn } 273a9cade51SNathan Whitehorn 274a9cade51SNathan Whitehorn static void 275c933841dSNathan Whitehorn kiic_setport(struct kiic_softc *sc, u_int port) 276c933841dSNathan Whitehorn { 277c933841dSNathan Whitehorn u_int x; 278c933841dSNathan Whitehorn 279c933841dSNathan Whitehorn KASSERT(port == 1 || port == 0, ("bad port")); 280c933841dSNathan Whitehorn x = kiic_readreg(sc, MODE); 281c933841dSNathan Whitehorn x &= ~I2C_PORT; 282c933841dSNathan Whitehorn x |= (port << 4); 283c933841dSNathan Whitehorn kiic_writereg(sc, MODE, x); 284c933841dSNathan Whitehorn } 285c933841dSNathan Whitehorn 286c933841dSNathan Whitehorn static void 287a9cade51SNathan Whitehorn kiic_setspeed(struct kiic_softc *sc, u_int speed) 288a9cade51SNathan Whitehorn { 289a9cade51SNathan Whitehorn u_int x; 290a9cade51SNathan Whitehorn 291a9cade51SNathan Whitehorn KASSERT((speed & ~I2C_SPEED) == 0, ("bad speed")); 292a9cade51SNathan Whitehorn x = kiic_readreg(sc, MODE); 293a9cade51SNathan Whitehorn x &= ~I2C_SPEED; 294a9cade51SNathan Whitehorn x |= speed; 295a9cade51SNathan Whitehorn kiic_writereg(sc, MODE, x); 296a9cade51SNathan Whitehorn } 297a9cade51SNathan Whitehorn 298a9cade51SNathan Whitehorn static void 299a9cade51SNathan Whitehorn kiic_intr(void *xsc) 300a9cade51SNathan Whitehorn { 301a9cade51SNathan Whitehorn struct kiic_softc *sc = xsc; 302a9cade51SNathan Whitehorn u_int isr; 303a9cade51SNathan Whitehorn uint32_t x; 304a9cade51SNathan Whitehorn 305a9cade51SNathan Whitehorn mtx_lock(&sc->sc_mutex); 306a9cade51SNathan Whitehorn isr = kiic_readreg(sc, ISR); 307a9cade51SNathan Whitehorn 308a9cade51SNathan Whitehorn if (isr & I2C_INT_ADDR) { 309a9cade51SNathan Whitehorn sc->sc_flags |= I2C_SELECTED; 310a9cade51SNathan Whitehorn 311a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_READING) { 312a9cade51SNathan Whitehorn if (sc->sc_resid > 1) { 313a9cade51SNathan Whitehorn x = kiic_readreg(sc, CONTROL); 314a9cade51SNathan Whitehorn x |= I2C_CT_AAK; 315a9cade51SNathan Whitehorn kiic_writereg(sc, CONTROL, x); 316a9cade51SNathan Whitehorn } 317a9cade51SNathan Whitehorn } else { 318a9cade51SNathan Whitehorn kiic_writereg(sc, DATA, *sc->sc_data++); 319a9cade51SNathan Whitehorn sc->sc_resid--; 320a9cade51SNathan Whitehorn } 321a9cade51SNathan Whitehorn } 322a9cade51SNathan Whitehorn 323a9cade51SNathan Whitehorn if (isr & I2C_INT_DATA) { 324a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_READING) { 325d0ed4b9dSNathan Whitehorn if (sc->sc_resid > 0) { 326a9cade51SNathan Whitehorn *sc->sc_data++ = kiic_readreg(sc, DATA); 327a9cade51SNathan Whitehorn sc->sc_resid--; 328d0ed4b9dSNathan Whitehorn } 329c933841dSNathan Whitehorn if (sc->sc_resid == 0) /* done */ 330c933841dSNathan Whitehorn kiic_writereg(sc, CONTROL, 0); 331d0ed4b9dSNathan Whitehorn } else { 332d0ed4b9dSNathan Whitehorn if (sc->sc_resid == 0) { 333d0ed4b9dSNathan Whitehorn x = kiic_readreg(sc, CONTROL); 334d0ed4b9dSNathan Whitehorn x |= I2C_CT_STOP; 335d0ed4b9dSNathan Whitehorn kiic_writereg(sc, CONTROL, x); 336a9cade51SNathan Whitehorn } else { 337a9cade51SNathan Whitehorn kiic_writereg(sc, DATA, *sc->sc_data++); 338a9cade51SNathan Whitehorn sc->sc_resid--; 339a9cade51SNathan Whitehorn } 340a9cade51SNathan Whitehorn } 341a9cade51SNathan Whitehorn } 342a9cade51SNathan Whitehorn 343a9cade51SNathan Whitehorn if (isr & I2C_INT_STOP) { 344a9cade51SNathan Whitehorn kiic_writereg(sc, CONTROL, 0); 345a9cade51SNathan Whitehorn sc->sc_flags &= ~I2C_SELECTED; 346a9cade51SNathan Whitehorn wakeup(sc->sc_dev); 347a9cade51SNathan Whitehorn } 348a9cade51SNathan Whitehorn 349a9cade51SNathan Whitehorn kiic_writereg(sc, ISR, isr); 350a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 351a9cade51SNathan Whitehorn } 352a9cade51SNathan Whitehorn 353a9cade51SNathan Whitehorn static int 354a9cade51SNathan Whitehorn kiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 355a9cade51SNathan Whitehorn { 356a9cade51SNathan Whitehorn struct kiic_softc *sc; 357d0ed4b9dSNathan Whitehorn int i, x, timo, err; 358c933841dSNathan Whitehorn uint16_t addr; 359c933841dSNathan Whitehorn uint8_t subaddr; 360a9cade51SNathan Whitehorn 361a9cade51SNathan Whitehorn sc = device_get_softc(dev); 362a9cade51SNathan Whitehorn timo = 100; 363c933841dSNathan Whitehorn subaddr = 0; 364a9cade51SNathan Whitehorn 365a9cade51SNathan Whitehorn mtx_lock(&sc->sc_mutex); 366a9cade51SNathan Whitehorn 367a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_BUSY) 368a9cade51SNathan Whitehorn mtx_sleep(dev, &sc->sc_mutex, 0, "kiic", timo); 369a9cade51SNathan Whitehorn 370a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_BUSY) { 371a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 372a9cade51SNathan Whitehorn return (ETIMEDOUT); 373a9cade51SNathan Whitehorn } 374a9cade51SNathan Whitehorn 375a9cade51SNathan Whitehorn sc->sc_flags = I2C_BUSY; 376a9cade51SNathan Whitehorn 377c933841dSNathan Whitehorn /* Clear pending interrupts, and reset controller */ 378c933841dSNathan Whitehorn kiic_writereg(sc, ISR, kiic_readreg(sc, ISR)); 379c933841dSNathan Whitehorn kiic_writereg(sc, STATUS, 0); 380c933841dSNathan Whitehorn 381a9cade51SNathan Whitehorn for (i = 0; i < nmsgs; i++) { 382c933841dSNathan Whitehorn if (msgs[i].flags & IIC_M_NOSTOP) { 383c933841dSNathan Whitehorn if (msgs[i+1].flags & IIC_M_RD) 384c933841dSNathan Whitehorn kiic_setmode(sc, I2C_COMBMODE); 385c933841dSNathan Whitehorn else 386c933841dSNathan Whitehorn kiic_setmode(sc, I2C_STDSUBMODE); 387c933841dSNathan Whitehorn KASSERT(msgs[i].len == 1, ("oversize I2C message")); 388c933841dSNathan Whitehorn subaddr = msgs[i].buf[0]; 389c933841dSNathan Whitehorn i++; 390c933841dSNathan Whitehorn } else { 391c933841dSNathan Whitehorn kiic_setmode(sc, I2C_STDMODE); 392c933841dSNathan Whitehorn } 393c933841dSNathan Whitehorn 394a9cade51SNathan Whitehorn sc->sc_data = msgs[i].buf; 395a9cade51SNathan Whitehorn sc->sc_resid = msgs[i].len; 396a9cade51SNathan Whitehorn sc->sc_flags = I2C_BUSY; 397a9cade51SNathan Whitehorn addr = msgs[i].slave; 398a9cade51SNathan Whitehorn timo = 1000 + sc->sc_resid * 200; 399d0ed4b9dSNathan Whitehorn timo += 100000; 400a9cade51SNathan Whitehorn 401a9cade51SNathan Whitehorn if (msgs[i].flags & IIC_M_RD) { 402a9cade51SNathan Whitehorn sc->sc_flags |= I2C_READING; 403a9cade51SNathan Whitehorn addr |= 1; 404a9cade51SNathan Whitehorn } 405a9cade51SNathan Whitehorn 406c933841dSNathan Whitehorn addr |= sc->sc_i2c_base; 407c933841dSNathan Whitehorn 408c933841dSNathan Whitehorn kiic_setport(sc, (addr & 0x100) >> 8); 409c933841dSNathan Whitehorn kiic_writereg(sc, ADDR, addr & 0xff); 410c933841dSNathan Whitehorn kiic_writereg(sc, SUBADDR, subaddr); 411a9cade51SNathan Whitehorn 412a9cade51SNathan Whitehorn x = kiic_readreg(sc, CONTROL) | I2C_CT_ADDR; 413a9cade51SNathan Whitehorn kiic_writereg(sc, CONTROL, x); 414a9cade51SNathan Whitehorn 415d0ed4b9dSNathan Whitehorn err = mtx_sleep(dev, &sc->sc_mutex, 0, "kiic", timo); 416a9cade51SNathan Whitehorn 417a9cade51SNathan Whitehorn msgs[i].len -= sc->sc_resid; 418a9cade51SNathan Whitehorn 419d0ed4b9dSNathan Whitehorn if ((sc->sc_flags & I2C_ERROR) || err == EWOULDBLOCK) { 420d0ed4b9dSNathan Whitehorn device_printf(sc->sc_dev, "I2C error\n"); 421d0ed4b9dSNathan Whitehorn sc->sc_flags = 0; 422a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 423b1397508SAndreas Tobler return (EIO); 424a9cade51SNathan Whitehorn } 425a9cade51SNathan Whitehorn } 426a9cade51SNathan Whitehorn 427a9cade51SNathan Whitehorn sc->sc_flags = 0; 428a9cade51SNathan Whitehorn 429a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 430a9cade51SNathan Whitehorn 431a9cade51SNathan Whitehorn return (0); 432a9cade51SNathan Whitehorn } 433a9cade51SNathan Whitehorn 434a9cade51SNathan Whitehorn static phandle_t 435a9cade51SNathan Whitehorn kiic_get_node(device_t bus, device_t dev) 436a9cade51SNathan Whitehorn { 437a9cade51SNathan Whitehorn struct kiic_softc *sc; 438a9cade51SNathan Whitehorn 439a9cade51SNathan Whitehorn sc = device_get_softc(bus); 440a9cade51SNathan Whitehorn /* We only have one child, the I2C bus, which needs our own node. */ 441a9cade51SNathan Whitehorn 442a9cade51SNathan Whitehorn return sc->sc_node; 443a9cade51SNathan Whitehorn } 444a9cade51SNathan Whitehorn 445