Annotation of sys/arch/sparc64/dev/pcfiic_ebus.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pcfiic_ebus.c,v 1.7 2007/05/21 03:11:11 jsg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * Device specific driver for the EBus i2c devices found on some sun4u
! 21: * systems. On systems not having a boot-bus controller the i2c devices
! 22: * are PCF8584.
! 23: */
! 24:
! 25: #include <sys/param.h>
! 26: #include <sys/systm.h>
! 27: #include <sys/device.h>
! 28: #include <sys/kernel.h>
! 29: #include <sys/rwlock.h>
! 30:
! 31: #include <machine/bus.h>
! 32: #include <machine/openfirm.h>
! 33: #include <machine/autoconf.h>
! 34:
! 35: #include <sparc64/dev/ebusreg.h>
! 36: #include <sparc64/dev/ebusvar.h>
! 37:
! 38: #include <dev/i2c/i2cvar.h>
! 39: #include <sparc64/dev/ofwi2cvar.h>
! 40:
! 41: #include <dev/ic/pcf8584var.h>
! 42:
! 43: int pcfiic_ebus_match(struct device *, void *, void *);
! 44: void pcfiic_ebus_attach(struct device *, struct device *, void *);
! 45:
! 46: struct pcfiic_ebus_softc {
! 47: struct pcfiic_softc esc_sc;
! 48:
! 49: int esc_node;
! 50: void *esc_ih;
! 51: };
! 52:
! 53: struct cfattach pcfiic_ebus_ca = {
! 54: sizeof(struct pcfiic_ebus_softc), pcfiic_ebus_match, pcfiic_ebus_attach
! 55: };
! 56:
! 57: int
! 58: pcfiic_ebus_match(struct device *parent, void *match, void *aux)
! 59: {
! 60: struct ebus_attach_args *ea = aux;
! 61: char compat[32];
! 62:
! 63: if (strcmp(ea->ea_name, "i2c") != 0)
! 64: return (0);
! 65:
! 66: if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1)
! 67: return (0);
! 68:
! 69: if (strcmp(compat, "i2cpcf,8584") ||
! 70: strcmp(compat, "SUNW,bbc-i2c"))
! 71: return (1);
! 72:
! 73: return (0);
! 74: }
! 75:
! 76: void
! 77: pcfiic_ebus_attach(struct device *parent, struct device *self, void *aux)
! 78: {
! 79: struct pcfiic_ebus_softc *esc = (struct pcfiic_ebus_softc *)self;
! 80: struct pcfiic_softc *sc = &esc->esc_sc;
! 81: struct ebus_attach_args *ea = aux;
! 82: char compat[32];
! 83: u_int64_t addr;
! 84: u_int8_t clock = PCF_CLOCK_12;
! 85: int swapregs = 0;
! 86:
! 87: if (ea->ea_nregs < 1 || ea->ea_nregs > 2) {
! 88: printf(": expected 1 or 2 registers, got %d\n", ea->ea_nregs);
! 89: return;
! 90: }
! 91:
! 92: if (OF_getprop(ea->ea_node, "compatible", compat, sizeof(compat)) == -1)
! 93: return;
! 94:
! 95: if (strcmp(compat, "SUNW,bbc-i2c") == 0) {
! 96: /*
! 97: * On BBC-based machines, Sun swapped the order of
! 98: * the registers on their clone pcf, plus they feed
! 99: * it a non-standard clock.
! 100: */
! 101: int clk = getpropint(findroot(), "clock-frequency", 0);
! 102:
! 103: if (clk < 105000000)
! 104: clock = PCF_CLOCK_3;
! 105: else if (clk < 160000000)
! 106: clock = PCF_CLOCK_4_43;
! 107: swapregs = 1;
! 108: }
! 109:
! 110: if (OF_getprop(ea->ea_node, "own-address", &addr, sizeof(addr)) == -1) {
! 111: addr = 0xaa;
! 112: } else if (addr == 0x00 || addr > 0xff) {
! 113: printf(": invalid address on I2C bus");
! 114: return;
! 115: }
! 116:
! 117: /* Prefer prom mapping, then memory mapping, then io mapping */
! 118: if (ea->ea_nvaddrs) {
! 119: if (bus_space_map(ea->ea_memtag, ea->ea_vaddrs[0], 0,
! 120: BUS_SPACE_MAP_PROMADDRESS, &sc->sc_ioh) != 0)
! 121: goto fail;
! 122: sc->sc_iot = ea->ea_memtag;
! 123: } else if (ebus_bus_map(ea->ea_memtag, 0,
! 124: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
! 125: ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
! 126: sc->sc_iot = ea->ea_memtag;
! 127: } else if (ebus_bus_map(ea->ea_iotag, 0,
! 128: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]),
! 129: ea->ea_regs[0].size, 0, 0, &sc->sc_ioh) == 0) {
! 130: sc->sc_iot = ea->ea_iotag;
! 131: } else {
! 132: fail:
! 133: printf(": can't map register space\n");
! 134: return;
! 135: }
! 136:
! 137: if (ea->ea_nregs == 2) {
! 138: /*
! 139: * Second register only occurs on BBC-based machines,
! 140: * and is likely not prom mapped
! 141: */
! 142: if (ebus_bus_map(sc->sc_iot, 0, EBUS_PADDR_FROM_REG(&ea->ea_regs[1]),
! 143: ea->ea_regs[1].size, 0, 0, &sc->sc_ioh2) != 0) {
! 144: printf(": can't map 2nd register space\n");
! 145: return;
! 146: }
! 147: sc->sc_master = 1;
! 148: }
! 149:
! 150: if (ea->ea_nintrs >= 1)
! 151: esc->esc_ih = bus_intr_establish(sc->sc_iot, ea->ea_intrs[0],
! 152: IPL_BIO, 0, pcfiic_intr, sc, self->dv_xname);
! 153: else
! 154: esc->esc_ih = NULL;
! 155:
! 156:
! 157: if (esc->esc_ih == NULL)
! 158: sc->sc_poll = 1;
! 159:
! 160: pcfiic_attach(sc, (i2c_addr_t)(addr >> 1), clock, swapregs,
! 161: ofwiic_scan, &ea->ea_node);
! 162: }
CVSweb