1a9cade51SNathan Whitehorn /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 371e3c308SPedro F. Giffuni * 4a9cade51SNathan Whitehorn * Copyright (c) 2001 Tsubai Masanari. All rights reserved. 5a9cade51SNathan Whitehorn * 6a9cade51SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 7a9cade51SNathan Whitehorn * modification, are permitted provided that the following conditions 8a9cade51SNathan Whitehorn * are met: 9a9cade51SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 10a9cade51SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 11a9cade51SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 12a9cade51SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 13a9cade51SNathan Whitehorn * documentation and/or other materials provided with the distribution. 14a9cade51SNathan Whitehorn * 3. The name of the author may not be used to endorse or promote products 15a9cade51SNathan Whitehorn * derived from this software without specific prior written permission. 16a9cade51SNathan Whitehorn * 17a9cade51SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18a9cade51SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19a9cade51SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20a9cade51SNathan Whitehorn * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21a9cade51SNathan Whitehorn * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22a9cade51SNathan Whitehorn * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23a9cade51SNathan Whitehorn * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24a9cade51SNathan Whitehorn * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25a9cade51SNathan Whitehorn * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26a9cade51SNathan Whitehorn * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 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 { 0, 0 } 139a9cade51SNathan Whitehorn }; 140a9cade51SNathan Whitehorn 141a9cade51SNathan Whitehorn static driver_t kiic_driver = { 142a9cade51SNathan Whitehorn "iichb", 143a9cade51SNathan Whitehorn kiic_methods, 144a9cade51SNathan Whitehorn sizeof(struct kiic_softc) 145a9cade51SNathan Whitehorn }; 146a9cade51SNathan Whitehorn 147992ae60bSJohn Baldwin DRIVER_MODULE(kiic, macio, kiic_driver, 0, 0); 148992ae60bSJohn Baldwin DRIVER_MODULE(kiic, unin, kiic_driver, 0, 0); 149a9cade51SNathan Whitehorn 150a9cade51SNathan Whitehorn static int 151a9cade51SNathan Whitehorn kiic_probe(device_t self) 152a9cade51SNathan Whitehorn { 153a9cade51SNathan Whitehorn const char *name; 154a9cade51SNathan Whitehorn 155a9cade51SNathan Whitehorn name = ofw_bus_get_name(self); 156a9cade51SNathan Whitehorn if (name && strcmp(name, "i2c") == 0) { 157a9cade51SNathan Whitehorn device_set_desc(self, "Keywest I2C controller"); 158a9cade51SNathan Whitehorn return (0); 159a9cade51SNathan Whitehorn } 160a9cade51SNathan Whitehorn 161a9cade51SNathan Whitehorn return (ENXIO); 162a9cade51SNathan Whitehorn } 163a9cade51SNathan Whitehorn 164a9cade51SNathan Whitehorn static int 165a9cade51SNathan Whitehorn kiic_attach(device_t self) 166a9cade51SNathan Whitehorn { 167a9cade51SNathan Whitehorn struct kiic_softc *sc = device_get_softc(self); 168a9cade51SNathan Whitehorn int rid, rate; 169a9cade51SNathan Whitehorn phandle_t node; 170a9cade51SNathan Whitehorn char name[64]; 171a9cade51SNathan Whitehorn 172a9cade51SNathan Whitehorn bzero(sc, sizeof(*sc)); 173a9cade51SNathan Whitehorn sc->sc_dev = self; 174a9cade51SNathan Whitehorn 175a9cade51SNathan Whitehorn node = ofw_bus_get_node(self); 176a9cade51SNathan Whitehorn if (node == 0 || node == -1) { 177a9cade51SNathan Whitehorn return (EINVAL); 178a9cade51SNathan Whitehorn } 179a9cade51SNathan Whitehorn 180a9cade51SNathan Whitehorn rid = 0; 181a9cade51SNathan Whitehorn sc->sc_reg = bus_alloc_resource_any(self, SYS_RES_MEMORY, 182a9cade51SNathan Whitehorn &rid, RF_ACTIVE); 183a9cade51SNathan Whitehorn if (sc->sc_reg == NULL) { 184a9cade51SNathan Whitehorn return (ENOMEM); 185a9cade51SNathan Whitehorn } 186a9cade51SNathan Whitehorn 187509142e1SNathan Whitehorn if (OF_getencprop(node, "AAPL,i2c-rate", &rate, 4) != 4) { 188a9cade51SNathan Whitehorn device_printf(self, "cannot get i2c-rate\n"); 189a9cade51SNathan Whitehorn return (ENXIO); 190a9cade51SNathan Whitehorn } 191509142e1SNathan Whitehorn if (OF_getencprop(node, "AAPL,address-step", &sc->sc_regstep, 4) != 4) { 192a9cade51SNathan Whitehorn device_printf(self, "unable to find i2c address step\n"); 193a9cade51SNathan Whitehorn return (ENXIO); 194a9cade51SNathan Whitehorn } 195a9cade51SNathan Whitehorn 196a9cade51SNathan Whitehorn /* 197a9cade51SNathan Whitehorn * Some Keywest I2C devices have their children attached directly 198a9cade51SNathan Whitehorn * underneath them. Some have a single 'iicbus' child with the 199a9cade51SNathan Whitehorn * devices underneath that. Sort this out, and make sure that the 200a9cade51SNathan Whitehorn * OFW I2C layer has the correct node. 201c933841dSNathan Whitehorn * 202c933841dSNathan Whitehorn * Note: the I2C children of the Uninorth bridges have two ports. 203c933841dSNathan Whitehorn * In general, the port is designated in the 9th bit of the I2C 204c933841dSNathan Whitehorn * address. However, for kiic devices with children attached below 205c933841dSNathan Whitehorn * an i2c-bus node, the port is indicated in the 'reg' property 206c933841dSNathan Whitehorn * of the i2c-bus node. 207a9cade51SNathan Whitehorn */ 208a9cade51SNathan Whitehorn 209a9cade51SNathan Whitehorn sc->sc_node = node; 210c933841dSNathan Whitehorn 211c933841dSNathan Whitehorn node = OF_child(node); 212c933841dSNathan Whitehorn if (OF_getprop(node, "name", name, sizeof(name)) > 0) { 213c933841dSNathan Whitehorn if (strcmp(name,"i2c-bus") == 0) { 214c933841dSNathan Whitehorn phandle_t reg; 215c933841dSNathan Whitehorn if (OF_getprop(node, "reg", ®, sizeof(reg)) > 0) 216c933841dSNathan Whitehorn sc->sc_i2c_base = reg << 8; 217c933841dSNathan Whitehorn 218c933841dSNathan Whitehorn sc->sc_node = node; 219c933841dSNathan Whitehorn } 220a9cade51SNathan Whitehorn } 221a9cade51SNathan Whitehorn 222a9cade51SNathan Whitehorn mtx_init(&sc->sc_mutex, "kiic", NULL, MTX_DEF); 223a9cade51SNathan Whitehorn 224a9cade51SNathan Whitehorn sc->sc_irq = bus_alloc_resource_any(self, SYS_RES_IRQ, &sc->sc_irqrid, 225a9cade51SNathan Whitehorn RF_ACTIVE); 226a9cade51SNathan Whitehorn bus_setup_intr(self, sc->sc_irq, INTR_TYPE_MISC | INTR_MPSAFE, NULL, 227a9cade51SNathan Whitehorn kiic_intr, sc, &sc->sc_ih); 228a9cade51SNathan Whitehorn 229c933841dSNathan Whitehorn kiic_writereg(sc, ISR, kiic_readreg(sc, ISR)); 230a9cade51SNathan Whitehorn kiic_writereg(sc, STATUS, 0); 231a9cade51SNathan Whitehorn kiic_writereg(sc, IER, 0); 232a9cade51SNathan Whitehorn 233a9cade51SNathan Whitehorn kiic_setmode(sc, I2C_STDMODE); 234a9cade51SNathan Whitehorn kiic_setspeed(sc, I2C_100kHz); /* XXX rate */ 235a9cade51SNathan Whitehorn 236a9cade51SNathan Whitehorn kiic_writereg(sc, IER, I2C_INT_DATA | I2C_INT_ADDR | I2C_INT_STOP); 237a9cade51SNathan Whitehorn 238c8812077SNathan Whitehorn if (bootverbose) 239c8812077SNathan Whitehorn device_printf(self, "Revision: %02X\n", kiic_readreg(sc, REV)); 240c8812077SNathan Whitehorn 241a9cade51SNathan Whitehorn /* Add the IIC bus layer */ 2425b56413dSWarner Losh sc->sc_iicbus = device_add_child(self, "iicbus", DEVICE_UNIT_ANY); 243a9cade51SNathan Whitehorn 244*18250ec6SJohn Baldwin bus_attach_children(self); 245*18250ec6SJohn Baldwin return (0); 246a9cade51SNathan Whitehorn } 247a9cade51SNathan Whitehorn 248a9cade51SNathan Whitehorn static void 249a9cade51SNathan Whitehorn kiic_writereg(struct kiic_softc *sc, u_int reg, u_int val) 250a9cade51SNathan Whitehorn { 251c8812077SNathan Whitehorn bus_write_4(sc->sc_reg, sc->sc_regstep * reg, val); 25223aa1a1dSAndreas Tobler DELAY(100); /* register access delay */ 253a9cade51SNathan Whitehorn } 254a9cade51SNathan Whitehorn 255a9cade51SNathan Whitehorn static u_int 256a9cade51SNathan Whitehorn kiic_readreg(struct kiic_softc *sc, u_int reg) 257a9cade51SNathan Whitehorn { 258c8812077SNathan Whitehorn return bus_read_4(sc->sc_reg, sc->sc_regstep * reg) & 0xff; 259a9cade51SNathan Whitehorn } 260a9cade51SNathan Whitehorn 261a9cade51SNathan Whitehorn static void 262a9cade51SNathan Whitehorn kiic_setmode(struct kiic_softc *sc, u_int mode) 263a9cade51SNathan Whitehorn { 264a9cade51SNathan Whitehorn u_int x; 265a9cade51SNathan Whitehorn 266a9cade51SNathan Whitehorn KASSERT((mode & ~I2C_MODE) == 0, ("bad mode")); 267a9cade51SNathan Whitehorn x = kiic_readreg(sc, MODE); 268a9cade51SNathan Whitehorn x &= ~I2C_MODE; 269a9cade51SNathan Whitehorn x |= mode; 270a9cade51SNathan Whitehorn kiic_writereg(sc, MODE, x); 271a9cade51SNathan Whitehorn } 272a9cade51SNathan Whitehorn 273a9cade51SNathan Whitehorn static void 274c933841dSNathan Whitehorn kiic_setport(struct kiic_softc *sc, u_int port) 275c933841dSNathan Whitehorn { 276c933841dSNathan Whitehorn u_int x; 277c933841dSNathan Whitehorn 278c933841dSNathan Whitehorn KASSERT(port == 1 || port == 0, ("bad port")); 279c933841dSNathan Whitehorn x = kiic_readreg(sc, MODE); 280c933841dSNathan Whitehorn x &= ~I2C_PORT; 281c933841dSNathan Whitehorn x |= (port << 4); 282c933841dSNathan Whitehorn kiic_writereg(sc, MODE, x); 283c933841dSNathan Whitehorn } 284c933841dSNathan Whitehorn 285c933841dSNathan Whitehorn static void 286a9cade51SNathan Whitehorn kiic_setspeed(struct kiic_softc *sc, u_int speed) 287a9cade51SNathan Whitehorn { 288a9cade51SNathan Whitehorn u_int x; 289a9cade51SNathan Whitehorn 290a9cade51SNathan Whitehorn KASSERT((speed & ~I2C_SPEED) == 0, ("bad speed")); 291a9cade51SNathan Whitehorn x = kiic_readreg(sc, MODE); 292a9cade51SNathan Whitehorn x &= ~I2C_SPEED; 293a9cade51SNathan Whitehorn x |= speed; 294a9cade51SNathan Whitehorn kiic_writereg(sc, MODE, x); 295a9cade51SNathan Whitehorn } 296a9cade51SNathan Whitehorn 297a9cade51SNathan Whitehorn static void 298a9cade51SNathan Whitehorn kiic_intr(void *xsc) 299a9cade51SNathan Whitehorn { 300a9cade51SNathan Whitehorn struct kiic_softc *sc = xsc; 301a9cade51SNathan Whitehorn u_int isr; 302a9cade51SNathan Whitehorn uint32_t x; 303a9cade51SNathan Whitehorn 304a9cade51SNathan Whitehorn mtx_lock(&sc->sc_mutex); 305a9cade51SNathan Whitehorn isr = kiic_readreg(sc, ISR); 306a9cade51SNathan Whitehorn 307a9cade51SNathan Whitehorn if (isr & I2C_INT_ADDR) { 308a9cade51SNathan Whitehorn sc->sc_flags |= I2C_SELECTED; 309a9cade51SNathan Whitehorn 310a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_READING) { 311a9cade51SNathan Whitehorn if (sc->sc_resid > 1) { 312a9cade51SNathan Whitehorn x = kiic_readreg(sc, CONTROL); 313a9cade51SNathan Whitehorn x |= I2C_CT_AAK; 314a9cade51SNathan Whitehorn kiic_writereg(sc, CONTROL, x); 315a9cade51SNathan Whitehorn } 316a9cade51SNathan Whitehorn } else { 317a9cade51SNathan Whitehorn kiic_writereg(sc, DATA, *sc->sc_data++); 318a9cade51SNathan Whitehorn sc->sc_resid--; 319a9cade51SNathan Whitehorn } 320a9cade51SNathan Whitehorn } 321a9cade51SNathan Whitehorn 322a9cade51SNathan Whitehorn if (isr & I2C_INT_DATA) { 323a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_READING) { 324d0ed4b9dSNathan Whitehorn if (sc->sc_resid > 0) { 325a9cade51SNathan Whitehorn *sc->sc_data++ = kiic_readreg(sc, DATA); 326a9cade51SNathan Whitehorn sc->sc_resid--; 327d0ed4b9dSNathan Whitehorn } 328c933841dSNathan Whitehorn if (sc->sc_resid == 0) /* done */ 329c933841dSNathan Whitehorn kiic_writereg(sc, CONTROL, 0); 330d0ed4b9dSNathan Whitehorn } else { 331d0ed4b9dSNathan Whitehorn if (sc->sc_resid == 0) { 332d0ed4b9dSNathan Whitehorn x = kiic_readreg(sc, CONTROL); 333d0ed4b9dSNathan Whitehorn x |= I2C_CT_STOP; 334d0ed4b9dSNathan Whitehorn kiic_writereg(sc, CONTROL, x); 335a9cade51SNathan Whitehorn } else { 336a9cade51SNathan Whitehorn kiic_writereg(sc, DATA, *sc->sc_data++); 337a9cade51SNathan Whitehorn sc->sc_resid--; 338a9cade51SNathan Whitehorn } 339a9cade51SNathan Whitehorn } 340a9cade51SNathan Whitehorn } 341a9cade51SNathan Whitehorn 342a9cade51SNathan Whitehorn if (isr & I2C_INT_STOP) { 343a9cade51SNathan Whitehorn kiic_writereg(sc, CONTROL, 0); 344a9cade51SNathan Whitehorn sc->sc_flags &= ~I2C_SELECTED; 345a9cade51SNathan Whitehorn wakeup(sc->sc_dev); 346a9cade51SNathan Whitehorn } 347a9cade51SNathan Whitehorn 348a9cade51SNathan Whitehorn kiic_writereg(sc, ISR, isr); 349a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 350a9cade51SNathan Whitehorn } 351a9cade51SNathan Whitehorn 352a9cade51SNathan Whitehorn static int 353a9cade51SNathan Whitehorn kiic_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 354a9cade51SNathan Whitehorn { 355a9cade51SNathan Whitehorn struct kiic_softc *sc; 356d0ed4b9dSNathan Whitehorn int i, x, timo, err; 357c933841dSNathan Whitehorn uint16_t addr; 358c933841dSNathan Whitehorn uint8_t subaddr; 359a9cade51SNathan Whitehorn 360a9cade51SNathan Whitehorn sc = device_get_softc(dev); 361a9cade51SNathan Whitehorn timo = 100; 362c933841dSNathan Whitehorn subaddr = 0; 363a9cade51SNathan Whitehorn 364a9cade51SNathan Whitehorn mtx_lock(&sc->sc_mutex); 365a9cade51SNathan Whitehorn 366a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_BUSY) 367a9cade51SNathan Whitehorn mtx_sleep(dev, &sc->sc_mutex, 0, "kiic", timo); 368a9cade51SNathan Whitehorn 369a9cade51SNathan Whitehorn if (sc->sc_flags & I2C_BUSY) { 370a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 371a9cade51SNathan Whitehorn return (ETIMEDOUT); 372a9cade51SNathan Whitehorn } 373a9cade51SNathan Whitehorn 374a9cade51SNathan Whitehorn sc->sc_flags = I2C_BUSY; 375a9cade51SNathan Whitehorn 376c933841dSNathan Whitehorn /* Clear pending interrupts, and reset controller */ 377c933841dSNathan Whitehorn kiic_writereg(sc, ISR, kiic_readreg(sc, ISR)); 378c933841dSNathan Whitehorn kiic_writereg(sc, STATUS, 0); 379c933841dSNathan Whitehorn 380a9cade51SNathan Whitehorn for (i = 0; i < nmsgs; i++) { 381c933841dSNathan Whitehorn if (msgs[i].flags & IIC_M_NOSTOP) { 382c933841dSNathan Whitehorn if (msgs[i+1].flags & IIC_M_RD) 383c933841dSNathan Whitehorn kiic_setmode(sc, I2C_COMBMODE); 384c933841dSNathan Whitehorn else 385c933841dSNathan Whitehorn kiic_setmode(sc, I2C_STDSUBMODE); 386c933841dSNathan Whitehorn KASSERT(msgs[i].len == 1, ("oversize I2C message")); 387c933841dSNathan Whitehorn subaddr = msgs[i].buf[0]; 388c933841dSNathan Whitehorn i++; 389c933841dSNathan Whitehorn } else { 390c933841dSNathan Whitehorn kiic_setmode(sc, I2C_STDMODE); 391c933841dSNathan Whitehorn } 392c933841dSNathan Whitehorn 393a9cade51SNathan Whitehorn sc->sc_data = msgs[i].buf; 394a9cade51SNathan Whitehorn sc->sc_resid = msgs[i].len; 395a9cade51SNathan Whitehorn sc->sc_flags = I2C_BUSY; 396a9cade51SNathan Whitehorn addr = msgs[i].slave; 397a9cade51SNathan Whitehorn timo = 1000 + sc->sc_resid * 200; 398d0ed4b9dSNathan Whitehorn timo += 100000; 399a9cade51SNathan Whitehorn 400a9cade51SNathan Whitehorn if (msgs[i].flags & IIC_M_RD) { 401a9cade51SNathan Whitehorn sc->sc_flags |= I2C_READING; 402a9cade51SNathan Whitehorn addr |= 1; 403a9cade51SNathan Whitehorn } 404a9cade51SNathan Whitehorn 405c933841dSNathan Whitehorn addr |= sc->sc_i2c_base; 406c933841dSNathan Whitehorn 407c933841dSNathan Whitehorn kiic_setport(sc, (addr & 0x100) >> 8); 408c933841dSNathan Whitehorn kiic_writereg(sc, ADDR, addr & 0xff); 409c933841dSNathan Whitehorn kiic_writereg(sc, SUBADDR, subaddr); 410a9cade51SNathan Whitehorn 411a9cade51SNathan Whitehorn x = kiic_readreg(sc, CONTROL) | I2C_CT_ADDR; 412a9cade51SNathan Whitehorn kiic_writereg(sc, CONTROL, x); 413a9cade51SNathan Whitehorn 414d0ed4b9dSNathan Whitehorn err = mtx_sleep(dev, &sc->sc_mutex, 0, "kiic", timo); 415a9cade51SNathan Whitehorn 416a9cade51SNathan Whitehorn msgs[i].len -= sc->sc_resid; 417a9cade51SNathan Whitehorn 418d0ed4b9dSNathan Whitehorn if ((sc->sc_flags & I2C_ERROR) || err == EWOULDBLOCK) { 419d0ed4b9dSNathan Whitehorn device_printf(sc->sc_dev, "I2C error\n"); 420d0ed4b9dSNathan Whitehorn sc->sc_flags = 0; 421a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 422b1397508SAndreas Tobler return (EIO); 423a9cade51SNathan Whitehorn } 424a9cade51SNathan Whitehorn } 425a9cade51SNathan Whitehorn 426a9cade51SNathan Whitehorn sc->sc_flags = 0; 427a9cade51SNathan Whitehorn 428a9cade51SNathan Whitehorn mtx_unlock(&sc->sc_mutex); 429a9cade51SNathan Whitehorn 430a9cade51SNathan Whitehorn return (0); 431a9cade51SNathan Whitehorn } 432a9cade51SNathan Whitehorn 433a9cade51SNathan Whitehorn static phandle_t 434a9cade51SNathan Whitehorn kiic_get_node(device_t bus, device_t dev) 435a9cade51SNathan Whitehorn { 436a9cade51SNathan Whitehorn struct kiic_softc *sc; 437a9cade51SNathan Whitehorn 438a9cade51SNathan Whitehorn sc = device_get_softc(bus); 439a9cade51SNathan Whitehorn /* We only have one child, the I2C bus, which needs our own node. */ 440a9cade51SNathan Whitehorn 441a9cade51SNathan Whitehorn return sc->sc_node; 442a9cade51SNathan Whitehorn } 443