[BACK]Return to pcfiic_ebus.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc64 / dev

Annotation of sys/arch/sparc64/dev/pcfiic_ebus.c, Revision 1.1.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