107829fe8Sbmercer /*
207829fe8Sbmercer * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
307829fe8Sbmercer *
407829fe8Sbmercer * Permission to use, copy, modify, and distribute this software for any
507829fe8Sbmercer * purpose with or without fee is hereby granted, provided that the above
607829fe8Sbmercer * copyright notice and this permission notice appear in all copies.
707829fe8Sbmercer *
807829fe8Sbmercer * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
907829fe8Sbmercer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1007829fe8Sbmercer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1107829fe8Sbmercer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1207829fe8Sbmercer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1307829fe8Sbmercer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1407829fe8Sbmercer * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1507829fe8Sbmercer */
1607829fe8Sbmercer
1707829fe8Sbmercer #include <sys/param.h>
1807829fe8Sbmercer #include <sys/systm.h>
19f326c416Skettenis #include <sys/device.h>
20f326c416Skettenis #include <sys/rwlock.h>
2107829fe8Sbmercer
22f326c416Skettenis #include <machine/bus.h>
23f326c416Skettenis #include <machine/fdt.h>
24f326c416Skettenis
25f326c416Skettenis #include <dev/ofw/openfirm.h>
26f326c416Skettenis #include <dev/ofw/ofw_pinctrl.h>
27f326c416Skettenis #include <dev/ofw/fdt.h>
28f326c416Skettenis
29f326c416Skettenis #include <dev/i2c/i2cvar.h>
30f326c416Skettenis
3107829fe8Sbmercer #include <armv7/exynos/exclockvar.h>
3207829fe8Sbmercer
3307829fe8Sbmercer /* registers */
3407829fe8Sbmercer #define I2C_CON 0x00 /* control register */
3507829fe8Sbmercer #define I2C_STAT 0x04 /* control/status register */
3607829fe8Sbmercer #define I2C_ADD 0x08 /* address register */
3707829fe8Sbmercer #define I2C_DS 0x0C /* transmit/receive data shift register */
3807829fe8Sbmercer #define I2C_LC 0x10 /* multi-master line control register */
3907829fe8Sbmercer
4007829fe8Sbmercer /* bits and bytes */
4107829fe8Sbmercer #define I2C_CON_TXCLKVAL_MASK (0xf << 0) /* tx clock = i2cclk / (i2ccon[3:0] + 1) */
4207829fe8Sbmercer #define I2C_CON_INTPENDING (0x1 << 4) /* 0 = no interrupt pending/clear, 1 = pending */
4307829fe8Sbmercer #define I2C_CON_TXRX_INT (0x1 << 5) /* enable/disable */
4407829fe8Sbmercer #define I2C_CON_TXCLKSRC_16 (0x0 << 6) /* i2clk = fpclk/16 */
4507829fe8Sbmercer #define I2C_CON_TXCLKSRC_512 (0x1 << 6) /* i2clk = fpclk/512 */
4607829fe8Sbmercer #define I2C_CON_ACK (0x1 << 7)
4707829fe8Sbmercer #define I2C_STAT_LAST_RVCD_BIT (0x1 << 0) /* last received bit 0 => ack, 1 => no ack */
4807829fe8Sbmercer #define I2C_STAT_ADDR_ZERO_FLAG (0x1 << 1) /* 0 => start/stop cond. detected, 1 => received slave addr 0xb */
4907829fe8Sbmercer #define I2C_STAT_ADDR_SLAVE_ZERO_FLAG (0x1 << 2) /* 0 => start/stop cond. detected, 1 => received slave addr matches i2cadd */
5036fd90dcSjsg #define I2C_STAT_ARBITRATION (0x1 << 3) /* 0 => successful, 1 => failed */
5107829fe8Sbmercer #define I2C_STAT_SERIAL_OUTPUT (0x1 << 4) /* 0 => disable tx/rx, 1 => enable tx/rx */
5207829fe8Sbmercer #define I2C_STAT_BUSY_SIGNAL (0x1 << 5) /* 0 => not busy / stop signal generation, 1 => busy / start signal generation */
5307829fe8Sbmercer #define I2C_STAT_MODE_SEL_SLAVE_RX (0x0 << 6) /* slave receive mode */
5407829fe8Sbmercer #define I2C_STAT_MODE_SEL_SLAVE_TX (0x1 << 6) /* slave transmit mode */
5507829fe8Sbmercer #define I2C_STAT_MODE_SEL_MASTER_RX (0x2 << 6) /* master receive mode */
5607829fe8Sbmercer #define I2C_STAT_MODE_SEL_MASTER_TX (0x3 << 6) /* master transmit */
5707829fe8Sbmercer #define I2C_ADD_SLAVE_ADDR(x) (((x) & 0x7f) << 1)
5807829fe8Sbmercer #define I2C_DS_DATA_SHIFT(x) (((x) & 0xff) << 0)
5907829fe8Sbmercer
6007829fe8Sbmercer #define I2C_ACK 0
6107829fe8Sbmercer #define I2C_NACK 1
6207829fe8Sbmercer #define I2C_TIMEOUT 2
6307829fe8Sbmercer
6407829fe8Sbmercer struct exiic_softc {
6507829fe8Sbmercer struct device sc_dev;
6607829fe8Sbmercer bus_space_tag_t sc_iot;
6707829fe8Sbmercer bus_space_handle_t sc_ioh;
6807829fe8Sbmercer bus_size_t sc_ios;
6907829fe8Sbmercer void *sc_ih;
70f326c416Skettenis int sc_node;
7107829fe8Sbmercer
7207829fe8Sbmercer struct rwlock sc_buslock;
7307829fe8Sbmercer struct i2c_controller i2c_tag;
7407829fe8Sbmercer
7507829fe8Sbmercer uint16_t frequency;
7607829fe8Sbmercer uint16_t intr_status;
7707829fe8Sbmercer };
7807829fe8Sbmercer
79f326c416Skettenis int exiic_match(struct device *, void *, void *);
8007829fe8Sbmercer void exiic_attach(struct device *, struct device *, void *);
8107829fe8Sbmercer int exiic_detach(struct device *, int);
82f326c416Skettenis void exiic_scan(struct device *, struct i2cbus_attach_args *, void *);
8307829fe8Sbmercer void exiic_setspeed(struct exiic_softc *, int);
8407829fe8Sbmercer int exiic_wait_state(struct exiic_softc *, uint32_t, uint32_t, uint32_t);
8507829fe8Sbmercer
8607829fe8Sbmercer void exiic_xfer_start(struct exiic_softc *);
8707829fe8Sbmercer int exiic_xfer_wait(struct exiic_softc *);
8807829fe8Sbmercer int exiic_i2c_acquire_bus(void *, int);
8907829fe8Sbmercer void exiic_i2c_release_bus(void *, int);
9007829fe8Sbmercer int exiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
9107829fe8Sbmercer void *, size_t, int);
9207829fe8Sbmercer
9307829fe8Sbmercer #define HREAD4(sc, reg) \
9407829fe8Sbmercer (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
9507829fe8Sbmercer #define HWRITE4(sc, reg, val) \
9607829fe8Sbmercer bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
9707829fe8Sbmercer #define HSET4(sc, reg, bits) \
9807829fe8Sbmercer HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
9907829fe8Sbmercer #define HCLR4(sc, reg, bits) \
10007829fe8Sbmercer HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
10107829fe8Sbmercer
10207829fe8Sbmercer
103*9fdf0c62Smpi const struct cfattach exiic_ca = {
10407829fe8Sbmercer sizeof(struct exiic_softc), exiic_match, exiic_attach, exiic_detach
10507829fe8Sbmercer };
10607829fe8Sbmercer
10707829fe8Sbmercer struct cfdriver exiic_cd = {
10807829fe8Sbmercer NULL, "exiic", DV_DULL
10907829fe8Sbmercer };
11007829fe8Sbmercer
11107829fe8Sbmercer int
exiic_match(struct device * parent,void * match,void * aux)112f326c416Skettenis exiic_match(struct device *parent, void *match, void *aux)
11307829fe8Sbmercer {
114f326c416Skettenis struct fdt_attach_args *faa = aux;
11507829fe8Sbmercer
116f326c416Skettenis return OF_is_compatible(faa->fa_node, "samsung,s3c2440-i2c");
11707829fe8Sbmercer }
11807829fe8Sbmercer
11907829fe8Sbmercer void
exiic_attach(struct device * parent,struct device * self,void * aux)120f326c416Skettenis exiic_attach(struct device *parent, struct device *self, void *aux)
12107829fe8Sbmercer {
12207829fe8Sbmercer struct exiic_softc *sc = (struct exiic_softc *)self;
123f326c416Skettenis struct fdt_attach_args *faa = aux;
124f326c416Skettenis struct i2cbus_attach_args iba;
12507829fe8Sbmercer
126f326c416Skettenis pinctrl_byname(faa->fa_node, "default");
12707829fe8Sbmercer
128f326c416Skettenis sc->sc_iot = faa->fa_iot;
129f326c416Skettenis sc->sc_node = faa->fa_node;
130f326c416Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
131f326c416Skettenis faa->fa_reg[0].size, 0, &sc->sc_ioh))
13207829fe8Sbmercer panic("%s: bus_space_map failed!", __func__);
13307829fe8Sbmercer
13407829fe8Sbmercer printf("\n");
13507829fe8Sbmercer
13607829fe8Sbmercer rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
13707829fe8Sbmercer
13807829fe8Sbmercer sc->i2c_tag.ic_cookie = sc;
13907829fe8Sbmercer sc->i2c_tag.ic_acquire_bus = exiic_i2c_acquire_bus;
14007829fe8Sbmercer sc->i2c_tag.ic_release_bus = exiic_i2c_release_bus;
14107829fe8Sbmercer sc->i2c_tag.ic_exec = exiic_i2c_exec;
14207829fe8Sbmercer
14307829fe8Sbmercer bzero(&iba, sizeof iba);
14407829fe8Sbmercer iba.iba_name = "iic";
14507829fe8Sbmercer iba.iba_tag = &sc->i2c_tag;
146f326c416Skettenis iba.iba_bus_scan = exiic_scan;
147f326c416Skettenis iba.iba_bus_scan_arg = &sc->sc_node;
14807829fe8Sbmercer config_found(&sc->sc_dev, &iba, NULL);
14907829fe8Sbmercer }
15007829fe8Sbmercer
15107829fe8Sbmercer void
exiic_scan(struct device * self,struct i2cbus_attach_args * iba,void * aux)152f326c416Skettenis exiic_scan(struct device *self, struct i2cbus_attach_args *iba, void *aux)
15307829fe8Sbmercer {
154f326c416Skettenis int iba_node = *(int *)aux;
155f326c416Skettenis extern int iic_print(void *, const char *);
15607829fe8Sbmercer struct i2c_attach_args ia;
157f326c416Skettenis char name[32];
158f326c416Skettenis uint32_t reg[1];
159f326c416Skettenis int node;
16007829fe8Sbmercer
161f326c416Skettenis for (node = OF_child(iba_node); node; node = OF_peer(node)) {
162f326c416Skettenis memset(name, 0, sizeof(name));
163f326c416Skettenis memset(reg, 0, sizeof(reg));
16407829fe8Sbmercer
165f326c416Skettenis if (OF_getprop(node, "compatible", name, sizeof(name)) == -1)
166f326c416Skettenis continue;
167f326c416Skettenis if (name[0] == '\0')
168f326c416Skettenis continue;
169f326c416Skettenis
170f326c416Skettenis if (OF_getprop(node, "reg", ®, sizeof(reg)) != sizeof(reg))
171f326c416Skettenis continue;
17207829fe8Sbmercer
17307829fe8Sbmercer memset(&ia, 0, sizeof(ia));
17407829fe8Sbmercer ia.ia_tag = iba->iba_tag;
175f326c416Skettenis ia.ia_addr = bemtoh32(®[0]);
17607829fe8Sbmercer ia.ia_name = name;
177f326c416Skettenis ia.ia_cookie = &node;
17807829fe8Sbmercer
179f326c416Skettenis config_found(self, &ia, iic_print);
180f326c416Skettenis }
18107829fe8Sbmercer }
18207829fe8Sbmercer
18307829fe8Sbmercer void
exiic_setspeed(struct exiic_softc * sc,int speed)18407829fe8Sbmercer exiic_setspeed(struct exiic_softc *sc, int speed)
18507829fe8Sbmercer {
18607829fe8Sbmercer if (!sc->frequency) {
18707829fe8Sbmercer uint32_t freq, div = 0, pres = 16;
18807829fe8Sbmercer freq = exclock_get_i2cclk();
18907829fe8Sbmercer
19007829fe8Sbmercer /* calculate prescaler and divisor values */
19107829fe8Sbmercer if ((freq / pres / (16 + 1)) > speed)
19207829fe8Sbmercer /* set prescaler to 512 */
19307829fe8Sbmercer pres = 512;
19407829fe8Sbmercer
19507829fe8Sbmercer while ((freq / pres / (div + 1)) > speed)
19607829fe8Sbmercer div++;
19707829fe8Sbmercer
19807829fe8Sbmercer /* set prescaler, divisor according to freq, also set ACKGEN, IRQ */
19907829fe8Sbmercer sc->frequency = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0);
20007829fe8Sbmercer }
20107829fe8Sbmercer
20207829fe8Sbmercer HWRITE4(sc, I2C_CON, sc->frequency);
20307829fe8Sbmercer }
20407829fe8Sbmercer
20507829fe8Sbmercer int
exiic_wait_state(struct exiic_softc * sc,uint32_t reg,uint32_t mask,uint32_t value)20607829fe8Sbmercer exiic_wait_state(struct exiic_softc *sc, uint32_t reg, uint32_t mask, uint32_t value)
20707829fe8Sbmercer {
20807829fe8Sbmercer uint32_t state;
20907829fe8Sbmercer int timeout;
21007829fe8Sbmercer state = HREAD4(sc, reg);
21107829fe8Sbmercer for (timeout = 1000; timeout > 0; timeout--) {
21207829fe8Sbmercer if (((state = HREAD4(sc, reg)) & mask) == value)
21307829fe8Sbmercer return 0;
21407829fe8Sbmercer delay(1000);
21507829fe8Sbmercer }
21607829fe8Sbmercer return ETIMEDOUT;
21707829fe8Sbmercer }
21807829fe8Sbmercer
21907829fe8Sbmercer int
exiic_i2c_acquire_bus(void * cookie,int flags)22007829fe8Sbmercer exiic_i2c_acquire_bus(void *cookie, int flags)
22107829fe8Sbmercer {
22207829fe8Sbmercer struct exiic_softc *sc = cookie;
22307829fe8Sbmercer int ret = rw_enter(&sc->sc_buslock, RW_WRITE);
22407829fe8Sbmercer
22507829fe8Sbmercer if (!ret) {
22607829fe8Sbmercer /* set speed to 100 Kbps */
22707829fe8Sbmercer exiic_setspeed(sc, 100);
22807829fe8Sbmercer
22907829fe8Sbmercer /* STOP */
23007829fe8Sbmercer HWRITE4(sc, I2C_STAT, 0);
23107829fe8Sbmercer HWRITE4(sc, I2C_ADD, 0);
23207829fe8Sbmercer HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_TX
23307829fe8Sbmercer | I2C_STAT_SERIAL_OUTPUT);
23407829fe8Sbmercer }
23507829fe8Sbmercer
23607829fe8Sbmercer return ret;
23707829fe8Sbmercer }
23807829fe8Sbmercer
23907829fe8Sbmercer void
exiic_i2c_release_bus(void * cookie,int flags)24007829fe8Sbmercer exiic_i2c_release_bus(void *cookie, int flags)
24107829fe8Sbmercer {
24207829fe8Sbmercer struct exiic_softc *sc = cookie;
24307829fe8Sbmercer
24407829fe8Sbmercer (void) rw_exit(&sc->sc_buslock);
24507829fe8Sbmercer }
24607829fe8Sbmercer
24707829fe8Sbmercer int
exiic_i2c_exec(void * cookie,i2c_op_t op,i2c_addr_t _addr,const void * cmdbuf,size_t cmdlen,void * databuf,size_t datalen,int flags)24807829fe8Sbmercer exiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t _addr,
24907829fe8Sbmercer const void *cmdbuf, size_t cmdlen, void *databuf, size_t datalen, int flags)
25007829fe8Sbmercer {
25107829fe8Sbmercer struct exiic_softc *sc = cookie;
25207829fe8Sbmercer uint32_t ret = 0;
25307829fe8Sbmercer u_int8_t addr = 0;
25407829fe8Sbmercer int i = 0;
25507829fe8Sbmercer
25607829fe8Sbmercer addr = (_addr & 0x7f) << 1;
25707829fe8Sbmercer
25807829fe8Sbmercer /* clock gating */
25907829fe8Sbmercer //exccm_enable_i2c(sc->unit);
26007829fe8Sbmercer
26107829fe8Sbmercer if (exiic_wait_state(sc, I2C_STAT, I2C_STAT_BUSY_SIGNAL, 0)) {
26207829fe8Sbmercer printf("%s: busy\n", __func__);
26307829fe8Sbmercer return (EIO);
26407829fe8Sbmercer }
26507829fe8Sbmercer
26607829fe8Sbmercer /* acknowledge generation */
26707829fe8Sbmercer HSET4(sc, I2C_CON, I2C_CON_ACK);
26807829fe8Sbmercer
26907829fe8Sbmercer /* Send the slave-address */
27007829fe8Sbmercer HWRITE4(sc, I2C_DS, addr);
27107829fe8Sbmercer if (!I2C_OP_READ_P(op) || (cmdbuf && cmdlen))
27207829fe8Sbmercer HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_TX
27307829fe8Sbmercer | I2C_STAT_SERIAL_OUTPUT
27407829fe8Sbmercer | I2C_STAT_BUSY_SIGNAL);
27507829fe8Sbmercer else
27607829fe8Sbmercer HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
27707829fe8Sbmercer | I2C_STAT_SERIAL_OUTPUT
27807829fe8Sbmercer | I2C_STAT_BUSY_SIGNAL);
27907829fe8Sbmercer
28007829fe8Sbmercer ret = exiic_xfer_wait(sc);
28107829fe8Sbmercer if (ret != I2C_ACK)
28207829fe8Sbmercer goto fail;
28307829fe8Sbmercer
28407829fe8Sbmercer /* transmit commands */
28507829fe8Sbmercer if (cmdbuf && cmdlen) {
28607829fe8Sbmercer for (i = 0; i < cmdlen; i++) {
28707829fe8Sbmercer HWRITE4(sc, I2C_DS, ((uint8_t *)cmdbuf)[i]);
28807829fe8Sbmercer exiic_xfer_start(sc);
28907829fe8Sbmercer ret = exiic_xfer_wait(sc);
29007829fe8Sbmercer if (ret != I2C_ACK)
29107829fe8Sbmercer goto fail;
29207829fe8Sbmercer }
29307829fe8Sbmercer }
29407829fe8Sbmercer
29507829fe8Sbmercer if (I2C_OP_READ_P(op)) {
29607829fe8Sbmercer if (cmdbuf && cmdlen) {
29707829fe8Sbmercer /* write slave chip address again for actual read */
29807829fe8Sbmercer HWRITE4(sc, I2C_DS, addr);
29907829fe8Sbmercer
30007829fe8Sbmercer /* restart */
30107829fe8Sbmercer HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
30207829fe8Sbmercer | I2C_STAT_SERIAL_OUTPUT
30307829fe8Sbmercer | I2C_STAT_BUSY_SIGNAL);
30407829fe8Sbmercer exiic_xfer_start(sc);
30507829fe8Sbmercer ret = exiic_xfer_wait(sc);
30607829fe8Sbmercer if (ret != I2C_ACK)
30707829fe8Sbmercer goto fail;
30807829fe8Sbmercer }
30907829fe8Sbmercer
31007829fe8Sbmercer for (i = 0; i < datalen && ret == I2C_ACK; i++) {
31107829fe8Sbmercer /* disable ACK for final read */
31207829fe8Sbmercer if (i == datalen - 1)
31307829fe8Sbmercer HCLR4(sc, I2C_CON, I2C_CON_ACK);
31407829fe8Sbmercer exiic_xfer_start(sc);
31507829fe8Sbmercer ret = exiic_xfer_wait(sc);
31607829fe8Sbmercer ((uint8_t *)databuf)[i] = HREAD4(sc, I2C_DS);
31707829fe8Sbmercer }
31807829fe8Sbmercer if (ret == I2C_NACK)
31907829fe8Sbmercer ret = I2C_ACK; /* Normal terminated read. */
32007829fe8Sbmercer } else {
32107829fe8Sbmercer for (i = 0; i < datalen && ret == I2C_ACK; i++) {
32207829fe8Sbmercer HWRITE4(sc, I2C_DS, ((uint8_t *)databuf)[i]);
32307829fe8Sbmercer exiic_xfer_start(sc);
32407829fe8Sbmercer ret = exiic_xfer_wait(sc);
32507829fe8Sbmercer }
32607829fe8Sbmercer }
32707829fe8Sbmercer
32807829fe8Sbmercer fail:
32907829fe8Sbmercer /* send STOP */
33007829fe8Sbmercer if (op & I2C_OP_READ_WITH_STOP) {
33107829fe8Sbmercer HWRITE4(sc, I2C_STAT, I2C_STAT_MODE_SEL_MASTER_RX
33207829fe8Sbmercer | I2C_STAT_SERIAL_OUTPUT);
33307829fe8Sbmercer exiic_xfer_start(sc);
33407829fe8Sbmercer }
33507829fe8Sbmercer
33607829fe8Sbmercer return ret;
33707829fe8Sbmercer }
33807829fe8Sbmercer
33907829fe8Sbmercer void
exiic_xfer_start(struct exiic_softc * sc)34007829fe8Sbmercer exiic_xfer_start(struct exiic_softc *sc)
34107829fe8Sbmercer {
34207829fe8Sbmercer HCLR4(sc, I2C_CON, I2C_CON_INTPENDING);
34307829fe8Sbmercer }
34407829fe8Sbmercer
34507829fe8Sbmercer int
exiic_xfer_wait(struct exiic_softc * sc)34607829fe8Sbmercer exiic_xfer_wait(struct exiic_softc *sc)
34707829fe8Sbmercer {
34807829fe8Sbmercer if (!exiic_wait_state(sc, I2C_CON, I2C_CON_INTPENDING,
34907829fe8Sbmercer I2C_CON_INTPENDING))
35007829fe8Sbmercer return (HREAD4(sc, I2C_STAT) & I2C_STAT_LAST_RVCD_BIT) ?
35107829fe8Sbmercer I2C_NACK : I2C_ACK;
35207829fe8Sbmercer else
35307829fe8Sbmercer return I2C_TIMEOUT;
35407829fe8Sbmercer }
35507829fe8Sbmercer
35607829fe8Sbmercer int
exiic_detach(struct device * self,int flags)35707829fe8Sbmercer exiic_detach(struct device *self, int flags)
35807829fe8Sbmercer {
35907829fe8Sbmercer struct exiic_softc *sc = (struct exiic_softc *)self;
36007829fe8Sbmercer
36107829fe8Sbmercer bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
36207829fe8Sbmercer return 0;
36307829fe8Sbmercer }
364