xref: /openbsd-src/sys/arch/armv7/exynos/exiic.c (revision 0f9e9ec23bb2b65cc62a3d17df12827a45dae80c)
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", &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(&reg[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