Home | History | Annotate | Line # | Download | only in i2c
motoi2c.c revision 1.2
      1 /* $NetBSD: motoi2c.c,v 1.2 2011/01/04 02:50:08 nisimura Exp $ */
      2 
      3 /*-
      4  * Copyright (c) 2007, 2010 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Matt Thomas.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: motoi2c.c,v 1.2 2011/01/04 02:50:08 nisimura Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/device.h>
     37 #include <sys/systm.h>
     38 #include <sys/mutex.h>
     39 #include <sys/bus.h>
     40 #include <sys/intr.h>
     41 
     42 #include <dev/i2c/i2cvar.h>
     43 #include <dev/i2c/motoi2creg.h>
     44 #include <dev/i2c/motoi2cvar.h>
     45 
     46 #ifdef DEBUG
     47 static int motoi2c_debug = 0;
     48 #define	DPRINTF		if (motoi2c_debug) printf
     49 #else
     50 #define	DPRINTF		(void)
     51 #endif
     52 
     53 static int  motoi2c_acquire_bus(void *, int);
     54 static void motoi2c_release_bus(void *, int);
     55 static int  motoi2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
     56 		void *, size_t, int);
     57 static int  motoi2c_busy_wait(struct motoi2c_softc *, uint8_t);
     58 
     59 static const struct i2c_controller motoi2c = {
     60 	.ic_acquire_bus = motoi2c_acquire_bus,
     61 	.ic_release_bus = motoi2c_release_bus,
     62 	.ic_exec	= motoi2c_exec,
     63 };
     64 
     65 static const struct motoi2c_settings motoi2c_default_settings = {
     66 	.i2c_adr	= MOTOI2C_ADR_DEFAULT,
     67 	.i2c_fdr	= MOTOI2C_FDR_DEFAULT,
     68 	.i2c_dfsrr	= MOTOI2C_DFSRR_DEFAULT,
     69 };
     70 
     71 #define	I2C_READ(r)	((*sc->sc_iord)(sc, (r)))
     72 #define	I2C_WRITE(r,v)	((*sc->sc_iowr)(sc, (r), (v)))
     73 #define I2C_SETCLR(r, s, c) \
     74 	((*sc->sc_iowr)(sc, (r), ((*sc->sc_iord)(sc, (r)) | (s)) & ~(c)))
     75 
     76 static uint8_t
     77 motoi2c_iord1(struct motoi2c_softc *sc, bus_size_t off)
     78 {
     79 	return bus_space_read_1(sc->sc_iot, sc->sc_ioh, off);
     80 }
     81 
     82 static void
     83 motoi2c_iowr1(struct motoi2c_softc *sc, bus_size_t off, uint8_t data)
     84 {
     85 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, data);
     86 }
     87 
     88 void
     89 motoi2c_attach_common(device_t self, struct motoi2c_softc *sc,
     90 	const struct motoi2c_settings *i2c)
     91 {
     92 	struct i2cbus_attach_args iba;
     93 
     94 	mutex_init(&sc->sc_buslock, MUTEX_DEFAULT, IPL_NONE);
     95 
     96 	if (i2c == NULL)
     97 		i2c = &motoi2c_default_settings;
     98 
     99 	sc->sc_i2c = motoi2c;
    100 	sc->sc_i2c.ic_cookie = sc;
    101 	sc->sc_start = false;
    102 	if (sc->sc_iord == NULL)
    103 		sc->sc_iord = motoi2c_iord1;
    104 	if (sc->sc_iowr == NULL)
    105 		sc->sc_iowr = motoi2c_iowr1;
    106 	memset(&iba, 0, sizeof(iba));
    107 	iba.iba_tag = &sc->sc_i2c;
    108 
    109 	I2C_WRITE(I2CCR, 0);		/* reset before changing anything */
    110 	I2C_WRITE(I2CDFSRR, i2c->i2c_dfsrr);	/* sampling units */
    111 	I2C_WRITE(I2CFDR, i2c->i2c_fdr);	/* divider 3072 (0x31) */
    112 	I2C_WRITE(I2CADR, i2c->i2c_adr);	/* our slave address is 0x7f */
    113 	I2C_WRITE(I2CSR, 0);		/* clear status flags */
    114 
    115 	config_found_ia(self, "i2cbus", &iba, iicbus_print);
    116 }
    117 
    118 static int
    119 motoi2c_acquire_bus(void *v, int flags)
    120 {
    121 	struct motoi2c_softc * const sc = v;
    122 
    123 	mutex_enter(&sc->sc_buslock);
    124 	I2C_WRITE(I2CCR, CR_MEN);	/* enable the I2C module */
    125 
    126 	return 0;
    127 }
    128 
    129 static void
    130 motoi2c_release_bus(void *v, int flags)
    131 {
    132 	struct motoi2c_softc * const sc = v;
    133 
    134 	sc->sc_start = false;
    135 	I2C_WRITE(I2CCR, 0);		/* reset before changing anything */
    136 	mutex_exit(&sc->sc_buslock);
    137 }
    138 
    139 /* busy waiting for byte data transfer completion */
    140 static int
    141 motoi2c_busy_wait(struct motoi2c_softc *sc, uint8_t cr)
    142 {
    143 	uint8_t sr;
    144 	u_int timo;
    145 	int error = 0;
    146 
    147 	timo = 1000;
    148 	while (((sr = I2C_READ(I2CSR)) & SR_MIF) == 0 && --timo)
    149 		DELAY(10);
    150 
    151 	if (timo == 0) {
    152 		DPRINTF("%s: timeout (sr=%#x, cr=%#x)\n",
    153 		    __func__, sr, I2C_READ(I2CCR));
    154 		error = ETIMEDOUT;
    155 	}
    156 	/*
    157 	 * RXAK is only valid when transmitting.
    158 	 */
    159 	if ((cr & CR_MTX) && (sr & SR_RXAK)) {
    160 		error = EIO;
    161 #ifdef DEBUG
    162 		DPRINTF("%s: missing rx ack (%#x): spin=%u\n",
    163 		    __func__, sr, 1000 - timo);
    164 #endif
    165 	}
    166 	I2C_WRITE(I2CSR, 0);
    167 	return error;
    168 }
    169 
    170 int
    171 motoi2c_intr(void *v)
    172 {
    173 	struct motoi2c_softc * const sc = v;
    174 
    175 	panic("%s(%p)", __func__, sc);
    176 
    177 	return 0;
    178 }
    179 
    180 int
    181 motoi2c_exec(void *v, i2c_op_t op, i2c_addr_t addr,
    182 	const void *cmdbuf, size_t cmdlen,
    183 	void *databuf, size_t datalen,
    184 	int flags)
    185 {
    186 	struct motoi2c_softc * const sc = v;
    187 	uint8_t sr;
    188 	uint8_t cr;
    189 	int error;
    190 
    191 	sr = I2C_READ(I2CSR);
    192 	cr = I2C_READ(I2CCR);
    193 
    194 #if 0
    195 	DPRINTF("%s(%#x,%#x,%p,%zu,%p,%zu,%#x): sr=%#x cr=%#x\n",
    196 	    __func__, op, addr, cmdbuf, cmdlen, databuf, datalen, flags,
    197 	    sr, cr);
    198 #endif
    199 
    200 	if ((cr & CR_MSTA) == 0 && (sr & SR_MBB) != 0) {
    201 		/* wait for bus becoming available */
    202 		u_int timo = 100;
    203 		do {
    204 			DELAY(10);
    205 		} while (--timo > 0 && ((sr = I2C_READ(I2CSR)) & SR_MBB) != 0);
    206 
    207 		if (timo == 0) {
    208 #ifdef DEBUG
    209 			DPRINTF("%s: bus is busy (%#x)\n", __func__, sr);
    210 #endif
    211 			return ETIMEDOUT;
    212 		}
    213 	}
    214 
    215 	/* reset interrupt and arbitration-lost flags (all others are RO) */
    216 	I2C_WRITE(I2CSR, 0);
    217 	sr = I2C_READ(I2CSR);
    218 
    219 	/*
    220 	 * Generate start (or restart) condition
    221 	 */
    222 	/* CR_RTSA is write-only and transitory */
    223 	uint8_t rsta = (cr & CR_MSTA ? CR_RSTA : 0);
    224 	cr = CR_MEN | CR_MTX | CR_MSTA;
    225 	I2C_WRITE(I2CCR, cr | rsta);
    226 
    227 	DPRINTF("%s: started: sr=%#x cr=%#x/%#x\n",
    228 	    __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR));
    229 
    230 	sr = I2C_READ(I2CSR);
    231 	if (sr & SR_MAL) {
    232 		DPRINTF("%s: lost bus: sr=%#x cr=%#x/%#x\n",
    233 		    __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR));
    234 		I2C_WRITE(I2CCR, 0);
    235 		DELAY(10);
    236 		I2C_WRITE(I2CCR, CR_MEN | CR_MTX | CR_MSTA);
    237 		DELAY(10);
    238 		sr = I2C_READ(I2CSR);
    239 		if (sr & SR_MAL) {
    240 			error = EBUSY;
    241 			goto out;
    242 		}
    243 		DPRINTF("%s: reacquired bus: sr=%#x cr=%#x/%#x\n",
    244 		    __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR));
    245 	}
    246 
    247 	/* send target address and transfer direction */
    248 	uint8_t addr_byte = (addr << 1)
    249 	    | (cmdlen == 0 && I2C_OP_READ_P(op) ? 1 : 0);
    250 	I2C_WRITE(I2CDR, addr_byte);
    251 
    252 	error = motoi2c_busy_wait(sc, cr);
    253 	if (error) {
    254 		DPRINTF("%s: error sending address: %d\n", __func__, error);
    255 		if (error == EIO)
    256 			error = ENXIO;
    257 		goto out;
    258 	}
    259 
    260 	const uint8_t *cmdptr = cmdbuf;
    261 	for (size_t i = 0; i < cmdlen; i++) {
    262 		I2C_WRITE(I2CDR, *cmdptr++);
    263 
    264 		error = motoi2c_busy_wait(sc, cr);
    265 		if (error) {
    266 			DPRINTF("%s: error sending cmd byte %zu (cr=%#x/%#x): %d\n",
    267 			    __func__, i, I2C_READ(I2CCR), cr, error);
    268 			goto out;
    269 		}
    270 	}
    271 
    272 	if (cmdlen > 0 && I2C_OP_READ_P(op)) {
    273 		KASSERT(cr & CR_MTX);
    274 		KASSERT((cr & CR_TXAK) == 0);
    275 		I2C_WRITE(I2CCR, cr | CR_RSTA);
    276 #if 0
    277 		DPRINTF("%s: restarted(read): sr=%#x cr=%#x(%#x)\n",
    278 		    __func__, I2C_READ(I2CSR), cr | CR_RSTA, I2C_READ(I2CCR));
    279 #endif
    280 
    281 		/* send target address and read transfer direction */
    282 		addr_byte |= 1;
    283 		I2C_WRITE(I2CDR, addr_byte);
    284 
    285 		error = motoi2c_busy_wait(sc, cr);
    286 		if (error) {
    287 			if (error == EIO)
    288 				error = ENXIO;
    289 			goto out;
    290 		}
    291 	}
    292 
    293 	if (I2C_OP_READ_P(op)) {
    294 		uint8_t *dataptr = databuf;
    295 		cr &= ~CR_MTX;		/* clear transmit flags */
    296 		if (datalen <= 1 && I2C_OP_STOP_P(op)) {
    297 			cr |= CR_TXAK;
    298 		}
    299 		I2C_WRITE(I2CCR, cr);
    300 		DELAY(10);
    301 		(void)I2C_READ(I2CDR);		/* dummy read */
    302 		for (size_t i = 0; i < datalen; i++) {
    303 			/*
    304 			 * If a master receiver wants to terminate a data
    305 			 * transfer, it must inform the slave transmitter by
    306 			 * not acknowledging the last byte of data (by setting
    307 			 * the transmit acknowledge bit (I2CCR[TXAK])) before
    308 			 * reading the next-to-last byte of data.
    309 			 */
    310 			error = motoi2c_busy_wait(sc, cr);
    311 			if (error) {
    312 				DPRINTF("%s: error reading byte %zu: %d\n",
    313 				    __func__, i, error);
    314 				goto out;
    315 			}
    316 			if (I2C_OP_STOP_P(op)) {
    317 				if (i == datalen - 2) {
    318 					cr |= CR_TXAK;
    319 					I2C_WRITE(I2CCR, cr);
    320 				} else if (i == datalen - 1) {
    321 					cr = CR_MEN;
    322 					I2C_WRITE(I2CCR, cr);
    323 					sc->sc_start = false;
    324 				}
    325 			}
    326 			*dataptr++ = I2C_READ(I2CDR);
    327 		}
    328 		if (datalen == 0) {
    329 			(void)I2C_READ(I2CDR);	/* dummy read */
    330 			error = motoi2c_busy_wait(sc, cr);
    331 			if (error) {
    332 				DPRINTF("%s: error reading dummy last byte: %d\n",
    333 				    __func__, error);
    334 				goto out;
    335 			}
    336 		}
    337 	} else {
    338 		const uint8_t *dataptr = databuf;
    339 		for (size_t i = 0; i < datalen; i++) {
    340 			I2C_WRITE(I2CDR, *dataptr++);
    341 			error = motoi2c_busy_wait(sc, cr);
    342 			if (error) {
    343 				DPRINTF("%s: error sending data byte %zu: %d\n",
    344 				    __func__, i, error);
    345 				goto out;
    346 			}
    347 		}
    348 	}
    349 
    350  out:
    351 	/*
    352 	 * If we encountered an error condition or caller wants a STOP,
    353 	 * send a STOP.
    354 	 */
    355 	if (error || (cr & CR_TXAK) || ((cr & CR_MSTA) && I2C_OP_STOP_P(op))) {
    356 		cr = CR_MEN;
    357 		I2C_WRITE(I2CCR, cr);
    358 		DPRINTF("%s: stopping: cr=%#x/%#x\n", __func__,
    359 		    cr, I2C_READ(I2CCR));
    360 	}
    361 
    362 	DPRINTF("%s: exit sr=%#x cr=%#x: %d\n", __func__,
    363 	    I2C_READ(I2CSR), I2C_READ(I2CCR), error);
    364 
    365 	return error;
    366 }
    367