Annotation of sys/arch/macppc/dev/kiic.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: kiic.c,v 1.2 2007/05/20 23:38:52 thib Exp $ */
! 2: /* $NetBSD: kiic.c,v 1.1 2003/12/27 02:19:34 grant Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2001 Tsubai Masanari. All rights reserved.
! 6: *
! 7: * Redistribution and use in source and binary forms, with or without
! 8: * modification, are permitted provided that the following conditions
! 9: * are met:
! 10: * 1. Redistributions of source code must retain the above copyright
! 11: * notice, this list of conditions and the following disclaimer.
! 12: * 2. Redistributions in binary form must reproduce the above copyright
! 13: * notice, this list of conditions and the following disclaimer in the
! 14: * documentation and/or other materials provided with the distribution.
! 15: * 3. The name of the author may not be used to endorse or promote products
! 16: * derived from this software without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 27: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: #include <sys/param.h>
! 31: #include <sys/device.h>
! 32: #include <sys/systm.h>
! 33:
! 34: #include <dev/ofw/openfirm.h>
! 35: #include <uvm/uvm_extern.h>
! 36: #include <machine/autoconf.h>
! 37:
! 38: #include <macppc/dev/kiicvar.h>
! 39: #include <macppc/dev/maci2cvar.h>
! 40:
! 41: int kiic_match(struct device *, void *, void *);
! 42: void kiic_attach(struct device *, struct device *, void *);
! 43: void kiic_attach_bus(struct kiic_softc *, struct kiic_bus *, int);
! 44: inline u_int kiic_readreg(struct kiic_softc *, int);
! 45: inline void kiic_writereg(struct kiic_softc *, int, u_int);
! 46: u_int kiic_getmode(struct kiic_softc *);
! 47: void kiic_setmode(struct kiic_softc *, u_int, u_int);
! 48: u_int kiic_getspeed(struct kiic_softc *);
! 49: void kiic_setspeed(struct kiic_softc *, u_int);
! 50: int kiic_intr(struct kiic_softc *);
! 51: int kiic_poll(struct kiic_softc *, int);
! 52: int kiic_start(struct kiic_softc *, int, int, void *, int);
! 53: int kiic_read(struct kiic_softc *, int, int, void *, int);
! 54: int kiic_write(struct kiic_softc *, int, int, const void *, int);
! 55:
! 56: /* I2C glue */
! 57: int kiic_i2c_acquire_bus(void *, int);
! 58: void kiic_i2c_release_bus(void *, int);
! 59: int kiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
! 60: void *, size_t, int);
! 61:
! 62: struct cfattach kiic_ca = {
! 63: sizeof(struct kiic_softc), kiic_match, kiic_attach
! 64: };
! 65: struct cfattach kiic_memc_ca = {
! 66: sizeof(struct kiic_softc), kiic_match, kiic_attach
! 67: };
! 68:
! 69: struct cfdriver kiic_cd = {
! 70: NULL, "kiic", DV_DULL
! 71: };
! 72:
! 73: int
! 74: kiic_match(struct device *parent, void *match, void *aux)
! 75: {
! 76: struct confargs *ca = aux;
! 77:
! 78: if (strcmp(ca->ca_name, "i2c") == 0 &&
! 79: ca->ca_nreg >= 4)
! 80: return (1);
! 81:
! 82: return (0);
! 83: }
! 84:
! 85: void
! 86: kiic_attach(struct device *parent, struct device *self, void *aux)
! 87: {
! 88: struct kiic_softc *sc = (struct kiic_softc *)self;
! 89: struct confargs *ca = aux;
! 90: int node = ca->ca_node;
! 91: int rate, count = 0;
! 92: char name[32];
! 93:
! 94: ca->ca_reg[0] += ca->ca_baseaddr;
! 95:
! 96: if (OF_getprop(node, "AAPL,i2c-rate", &rate, 4) != 4) {
! 97: printf(": cannot get i2c-rate\n");
! 98: return;
! 99: }
! 100: if (OF_getprop(node, "AAPL,address", &sc->sc_paddr, 4) != 4) {
! 101: printf(": unable to find i2c address\n");
! 102: return;
! 103: }
! 104: if (OF_getprop(node, "AAPL,address-step", &sc->sc_regstep, 4) != 4) {
! 105: printf(": unable to find i2c address step\n");
! 106: return;
! 107: }
! 108: sc->sc_reg = mapiodev(sc->sc_paddr, (DATA+1)*sc->sc_regstep);
! 109:
! 110: printf("\n");
! 111:
! 112: kiic_writereg(sc, STATUS, 0);
! 113: kiic_writereg(sc, ISR, 0);
! 114: kiic_writereg(sc, IER, 0);
! 115:
! 116: kiic_setmode(sc, I2C_STDSUBMODE, 0);
! 117: kiic_setspeed(sc, I2C_100kHz); /* XXX rate */
! 118:
! 119: rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
! 120: kiic_writereg(sc, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP);
! 121:
! 122: for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) {
! 123: if (OF_getprop(node, "name", &name, sizeof name) > 0) {
! 124: if (strcmp(name, "i2c-bus") == 0) {
! 125: kiic_attach_bus(sc, &sc->sc_bus[count], node);
! 126: if (++count >= KIIC_MAX_BUSSES)
! 127: break;
! 128: }
! 129: }
! 130: }
! 131:
! 132: /*
! 133: * If we didn't find any i2c-bus nodes, there is only a single
! 134: * i2c bus.
! 135: */
! 136:
! 137: if (count == 0)
! 138: kiic_attach_bus(sc, &sc->sc_bus[0], ca->ca_node);
! 139: }
! 140:
! 141: void
! 142: kiic_attach_bus(struct kiic_softc *sc, struct kiic_bus *bus, int node)
! 143: {
! 144: struct i2cbus_attach_args iba;
! 145: u_int32_t reg;
! 146:
! 147: if (OF_getprop(node, "reg", ®, sizeof reg) != sizeof reg)
! 148: return;
! 149:
! 150: bus->sc = sc;
! 151: bus->i2c_tag.ic_cookie = bus;
! 152: bus->i2c_tag.ic_acquire_bus = kiic_i2c_acquire_bus;
! 153: bus->i2c_tag.ic_release_bus = kiic_i2c_release_bus;
! 154: bus->i2c_tag.ic_exec = kiic_i2c_exec;
! 155: bus->reg = reg;
! 156:
! 157: bzero(&iba, sizeof iba);
! 158: iba.iba_name = "iic";
! 159: iba.iba_tag = &bus->i2c_tag;
! 160: iba.iba_bus_scan = maciic_scan;
! 161: iba.iba_bus_scan_arg = &node;
! 162: config_found(&sc->sc_dev, &iba, NULL);
! 163: }
! 164:
! 165: u_int
! 166: kiic_readreg(struct kiic_softc *sc, int reg)
! 167: {
! 168: u_char *addr = sc->sc_reg + sc->sc_regstep * reg;
! 169:
! 170: return (*addr);
! 171: }
! 172:
! 173: void
! 174: kiic_writereg(struct kiic_softc *sc, int reg, u_int val)
! 175: {
! 176: u_char *addr = sc->sc_reg + sc->sc_regstep * reg;
! 177:
! 178: *addr = val;
! 179: asm volatile ("eieio");
! 180: delay(10);
! 181: }
! 182:
! 183: u_int
! 184: kiic_getmode(struct kiic_softc *sc)
! 185: {
! 186: return kiic_readreg(sc, MODE) & I2C_MODE;
! 187: }
! 188:
! 189: void
! 190: kiic_setmode(struct kiic_softc *sc, u_int mode, u_int bus)
! 191: {
! 192: u_int x;
! 193:
! 194: KASSERT((mode & ~I2C_MODE) == 0);
! 195: x = kiic_readreg(sc, MODE);
! 196: x &= ~(I2C_MODE);
! 197: if (bus)
! 198: x |= I2C_BUS1;
! 199: else
! 200: x &= ~I2C_BUS1;
! 201: x |= mode;
! 202: kiic_writereg(sc, MODE, x);
! 203: }
! 204:
! 205: u_int
! 206: kiic_getspeed(struct kiic_softc *sc)
! 207: {
! 208: return kiic_readreg(sc, MODE) & I2C_SPEED;
! 209: }
! 210:
! 211: void
! 212: kiic_setspeed(struct kiic_softc *sc, u_int speed)
! 213: {
! 214: u_int x;
! 215:
! 216: KASSERT((speed & ~I2C_SPEED) == 0);
! 217: x = kiic_readreg(sc, MODE);
! 218: x &= ~I2C_SPEED;
! 219: x |= speed;
! 220: kiic_writereg(sc, MODE, x);
! 221: }
! 222:
! 223: int
! 224: kiic_intr(struct kiic_softc *sc)
! 225: {
! 226: u_int isr, x;
! 227:
! 228: isr = kiic_readreg(sc, ISR);
! 229: if (isr & I2C_INT_ADDR) {
! 230: #if 0
! 231: if ((kiic_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) {
! 232: /* No slave responded. */
! 233: sc->sc_flags |= I2C_ERROR;
! 234: goto out;
! 235: }
! 236: #endif
! 237:
! 238: if (sc->sc_flags & I2C_READING) {
! 239: if (sc->sc_resid > 1) {
! 240: x = kiic_readreg(sc, CONTROL);
! 241: x |= I2C_CT_AAK;
! 242: kiic_writereg(sc, CONTROL, x);
! 243: }
! 244: } else {
! 245: kiic_writereg(sc, DATA, *sc->sc_data++);
! 246: sc->sc_resid--;
! 247: }
! 248: }
! 249:
! 250: if (isr & I2C_INT_DATA) {
! 251: if (sc->sc_flags & I2C_READING) {
! 252: *sc->sc_data++ = kiic_readreg(sc, DATA);
! 253: sc->sc_resid--;
! 254:
! 255: if (sc->sc_resid == 0) { /* Completed */
! 256: kiic_writereg(sc, CONTROL, 0);
! 257: goto out;
! 258: }
! 259: } else {
! 260: #if 0
! 261: if ((kiic_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) {
! 262: /* No slave responded. */
! 263: sc->sc_flags |= I2C_ERROR;
! 264: goto out;
! 265: }
! 266: #endif
! 267:
! 268: if (sc->sc_resid == 0) {
! 269: x = kiic_readreg(sc, CONTROL) | I2C_CT_STOP;
! 270: kiic_writereg(sc, CONTROL, x);
! 271: } else {
! 272: kiic_writereg(sc, DATA, *sc->sc_data++);
! 273: sc->sc_resid--;
! 274: }
! 275: }
! 276: }
! 277:
! 278: out:
! 279: if (isr & I2C_INT_STOP) {
! 280: kiic_writereg(sc, CONTROL, 0);
! 281: sc->sc_flags &= ~I2C_BUSY;
! 282: }
! 283:
! 284: kiic_writereg(sc, ISR, isr);
! 285:
! 286: return (1);
! 287: }
! 288:
! 289: int
! 290: kiic_poll(struct kiic_softc *sc, int timo)
! 291: {
! 292: while (sc->sc_flags & I2C_BUSY) {
! 293: if (kiic_readreg(sc, ISR))
! 294: kiic_intr(sc);
! 295: timo -= 100;
! 296: if (timo < 0) {
! 297: printf("i2c_poll: timeout\n");
! 298: return (-1);
! 299: }
! 300: delay(100);
! 301: }
! 302: return (0);
! 303: }
! 304:
! 305: int
! 306: kiic_start(struct kiic_softc *sc, int addr, int subaddr, void *data, int len)
! 307: {
! 308: int rw = (sc->sc_flags & I2C_READING) ? 1 : 0;
! 309: int timo, x;
! 310:
! 311: KASSERT((addr & 1) == 0);
! 312:
! 313: sc->sc_data = data;
! 314: sc->sc_resid = len;
! 315: sc->sc_flags |= I2C_BUSY;
! 316:
! 317: timo = 1000 + len * 200;
! 318:
! 319: /* XXX TAS3001 sometimes takes 50ms to finish writing registers. */
! 320: /* if (addr == 0x68) */
! 321: timo += 100000;
! 322:
! 323: kiic_writereg(sc, ADDR, addr | rw);
! 324: kiic_writereg(sc, SUBADDR, subaddr);
! 325:
! 326: x = kiic_readreg(sc, CONTROL) | I2C_CT_ADDR;
! 327: kiic_writereg(sc, CONTROL, x);
! 328:
! 329: if (kiic_poll(sc, timo))
! 330: return (-1);
! 331: if (sc->sc_flags & I2C_ERROR) {
! 332: printf("I2C_ERROR\n");
! 333: return (-1);
! 334: }
! 335: return (0);
! 336: }
! 337:
! 338: int
! 339: kiic_read(struct kiic_softc *sc, int addr, int subaddr, void *data, int len)
! 340: {
! 341: sc->sc_flags = I2C_READING;
! 342: return kiic_start(sc, addr, subaddr, data, len);
! 343: }
! 344:
! 345: int
! 346: kiic_write(struct kiic_softc *sc, int addr, int subaddr, const void *data, int len)
! 347: {
! 348: sc->sc_flags = 0;
! 349: return kiic_start(sc, addr, subaddr, (void *)data, len);
! 350: }
! 351:
! 352: int
! 353: kiic_i2c_acquire_bus(void *cookie, int flags)
! 354: {
! 355: struct kiic_bus *bus = cookie;
! 356:
! 357: return (rw_enter(&bus->sc->sc_buslock, RW_WRITE));
! 358: }
! 359:
! 360: void
! 361: kiic_i2c_release_bus(void *cookie, int flags)
! 362: {
! 363: struct kiic_bus *bus = cookie;
! 364:
! 365: (void) rw_exit(&bus->sc->sc_buslock);
! 366: }
! 367:
! 368: int
! 369: kiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
! 370: const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
! 371: {
! 372: struct kiic_bus *bus = cookie;
! 373: u_int mode = I2C_STDSUBMODE;
! 374: u_int8_t cmd = 0;
! 375:
! 376: if (!I2C_OP_STOP_P(op) || cmdlen > 1)
! 377: return (EINVAL);
! 378:
! 379: if (cmdlen == 0)
! 380: mode = I2C_STDMODE;
! 381: else if (I2C_OP_READ_P(op))
! 382: mode = I2C_COMBMODE;
! 383:
! 384: if (cmdlen > 0)
! 385: cmd = *(u_int8_t *)cmdbuf;
! 386:
! 387: kiic_setmode(bus->sc, mode, bus->reg || addr & 0x80);
! 388: addr &= 0x7f;
! 389:
! 390: if (I2C_OP_READ_P(op)) {
! 391: if (kiic_read(bus->sc, (addr << 1), cmd, buf, len) != 0)
! 392: return (EIO);
! 393: } else {
! 394: if (kiic_write(bus->sc, (addr << 1), cmd, buf, len) != 0)
! 395: return (EIO);
! 396: }
! 397: return (0);
! 398: }
CVSweb