Home | History | Annotate | Line # | Download | only in broadcom
bcm2835_bsc.c revision 1.15.22.1
      1  1.15.22.1     skrll /*	$NetBSD: bcm2835_bsc.c,v 1.15.22.1 2024/02/16 12:08:02 skrll Exp $	*/
      2        1.1  jakllsch 
      3        1.1  jakllsch /*
      4       1.14   thorpej  * Copyright (c) 2019 Jason R. Thorpe
      5        1.1  jakllsch  * Copyright (c) 2012 Jonathan A. Kollasch
      6        1.1  jakllsch  * All rights reserved.
      7        1.1  jakllsch  *
      8        1.1  jakllsch  * Redistribution and use in source and binary forms, with or without
      9        1.1  jakllsch  * modification, are permitted provided that the following conditions
     10        1.1  jakllsch  * are met:
     11        1.1  jakllsch  * 1. Redistributions of source code must retain the above copyright
     12        1.1  jakllsch  *    notice, this list of conditions and the following disclaimer.
     13        1.1  jakllsch  * 2. Redistributions in binary form must reproduce the above copyright
     14        1.1  jakllsch  *    notice, this list of conditions and the following disclaimer in the
     15        1.1  jakllsch  *    documentation and/or other materials provided with the distribution.
     16        1.1  jakllsch  *
     17        1.1  jakllsch  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     18        1.1  jakllsch  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19        1.1  jakllsch  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20        1.1  jakllsch  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
     21        1.1  jakllsch  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     22        1.1  jakllsch  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     23        1.1  jakllsch  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     24        1.1  jakllsch  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25        1.1  jakllsch  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     26        1.1  jakllsch  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     27        1.1  jakllsch  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28        1.1  jakllsch  */
     29        1.1  jakllsch 
     30        1.1  jakllsch #include <sys/cdefs.h>
     31  1.15.22.1     skrll __KERNEL_RCSID(0, "$NetBSD: bcm2835_bsc.c,v 1.15.22.1 2024/02/16 12:08:02 skrll Exp $");
     32        1.1  jakllsch 
     33        1.1  jakllsch #include <sys/param.h>
     34        1.3     skrll #include <sys/bus.h>
     35        1.1  jakllsch #include <sys/device.h>
     36        1.8     skrll #include <sys/kernhist.h>
     37        1.3     skrll #include <sys/intr.h>
     38        1.3     skrll #include <sys/mutex.h>
     39        1.1  jakllsch #include <sys/systm.h>
     40        1.1  jakllsch 
     41        1.1  jakllsch #include <dev/i2c/i2cvar.h>
     42        1.1  jakllsch 
     43        1.1  jakllsch #include <arm/broadcom/bcm2835reg.h>
     44        1.1  jakllsch #include <arm/broadcom/bcm2835_bscreg.h>
     45       1.15  jmcneill #include <arm/broadcom/bcm2835_bscvar.h>
     46       1.14   thorpej 
     47       1.14   thorpej static void	bsciic_exec_func_idle(struct bsciic_softc * const);
     48       1.14   thorpej static void	bsciic_exec_func_send_addr(struct bsciic_softc * const);
     49       1.14   thorpej static void	bsciic_exec_func_send_cmd(struct bsciic_softc * const);
     50       1.14   thorpej static void	bsciic_exec_func_send_data(struct bsciic_softc * const);
     51       1.14   thorpej static void	bsciic_exec_func_recv_data(struct bsciic_softc * const);
     52       1.14   thorpej static void	bsciic_exec_func_done(struct bsciic_softc * const);
     53       1.14   thorpej static void	bsciic_exec_func_error(struct bsciic_softc * const);
     54       1.14   thorpej 
     55       1.14   thorpej const struct {
     56       1.14   thorpej 	void			(*func)(struct bsciic_softc * const);
     57       1.14   thorpej 	uint32_t		c_bits;
     58       1.14   thorpej 	uint32_t		s_bits;
     59       1.14   thorpej } bsciic_exec_state_data[] = {
     60       1.14   thorpej 	[BSC_EXEC_STATE_IDLE] = {
     61       1.14   thorpej 		.func = bsciic_exec_func_idle,
     62       1.14   thorpej 	},
     63       1.14   thorpej 	[BSC_EXEC_STATE_SEND_ADDR] = {
     64       1.14   thorpej 		.func = bsciic_exec_func_send_addr,
     65       1.14   thorpej 	},
     66       1.14   thorpej 	[BSC_EXEC_STATE_SEND_CMD] = {
     67       1.14   thorpej 		.func = bsciic_exec_func_send_cmd,
     68       1.14   thorpej 		.c_bits = BSC_C_INTT,
     69       1.14   thorpej 		.s_bits = BSC_S_TXW,
     70       1.14   thorpej 	},
     71       1.14   thorpej 	[BSC_EXEC_STATE_SEND_DATA] = {
     72       1.14   thorpej 		.func = bsciic_exec_func_send_data,
     73       1.14   thorpej 		.c_bits = BSC_C_INTT,
     74       1.14   thorpej 		.s_bits = BSC_S_TXW,
     75       1.14   thorpej 	},
     76       1.14   thorpej 	[BSC_EXEC_STATE_RECV_DATA] = {
     77       1.14   thorpej 		.func = bsciic_exec_func_recv_data,
     78       1.14   thorpej 		.c_bits = BSC_C_READ | BSC_C_INTR,
     79       1.14   thorpej 		.s_bits = BSC_S_RXR,
     80       1.14   thorpej 	},
     81       1.14   thorpej 	[BSC_EXEC_STATE_DONE] = {
     82       1.14   thorpej 		.func = bsciic_exec_func_done,
     83       1.14   thorpej 	},
     84       1.14   thorpej 	[BSC_EXEC_STATE_ERROR] = {
     85       1.14   thorpej 		.func = bsciic_exec_func_error,
     86       1.14   thorpej 	},
     87        1.1  jakllsch };
     88        1.1  jakllsch 
     89       1.14   thorpej int	bsciic_debug = 0;
     90        1.1  jakllsch 
     91       1.15  jmcneill void
     92       1.15  jmcneill bsciic_attach(struct bsciic_softc *sc)
     93        1.1  jakllsch {
     94       1.15  jmcneill 	mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_VM);
     95       1.15  jmcneill 	cv_init(&sc->sc_intr_wait, device_xname(sc->sc_dev));
     96        1.8     skrll 
     97        1.1  jakllsch 	/* clear FIFO, disable controller */
     98        1.1  jakllsch 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_CLEAR_CLEAR);
     99        1.1  jakllsch 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, BSC_S_CLKT |
    100        1.1  jakllsch 	    BSC_S_ERR | BSC_S_DONE);
    101       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, 0);
    102        1.8     skrll 
    103        1.8     skrll 	u_int divider = howmany(sc->sc_frequency, sc->sc_clkrate);
    104        1.1  jakllsch 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DIV,
    105        1.8     skrll 	   __SHIFTIN(divider, BSC_DIV_CDIV));
    106        1.1  jakllsch }
    107        1.1  jakllsch 
    108       1.15  jmcneill int
    109        1.1  jakllsch bsciic_acquire_bus(void *v, int flags)
    110        1.1  jakllsch {
    111        1.1  jakllsch 	struct bsciic_softc * const sc = v;
    112        1.2     ozaki 	uint32_t s __diagused;
    113        1.1  jakllsch 
    114        1.1  jakllsch 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S, BSC_S_CLKT |
    115        1.1  jakllsch 	    BSC_S_ERR | BSC_S_DONE);
    116        1.1  jakllsch 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_I2CEN |
    117        1.1  jakllsch 	    BSC_C_CLEAR_CLEAR);
    118        1.1  jakllsch 	s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
    119        1.1  jakllsch 	KASSERT((s & BSC_S_TA) == 0);
    120        1.1  jakllsch 
    121        1.1  jakllsch 	return 0;
    122        1.1  jakllsch }
    123        1.1  jakllsch 
    124       1.15  jmcneill void
    125        1.1  jakllsch bsciic_release_bus(void *v, int flags)
    126        1.1  jakllsch {
    127        1.1  jakllsch 	struct bsciic_softc * const sc = v;
    128        1.1  jakllsch 
    129        1.1  jakllsch 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_CLEAR_CLEAR);
    130       1.14   thorpej }
    131        1.1  jakllsch 
    132       1.14   thorpej static void
    133       1.14   thorpej bsciic_exec_lock(struct bsciic_softc * const sc)
    134       1.14   thorpej {
    135       1.14   thorpej 	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
    136       1.14   thorpej 		mutex_enter(&sc->sc_intr_lock);
    137       1.14   thorpej 	}
    138        1.1  jakllsch }
    139        1.1  jakllsch 
    140       1.14   thorpej static void
    141       1.14   thorpej bsciic_exec_unlock(struct bsciic_softc * const sc)
    142       1.14   thorpej {
    143       1.14   thorpej 	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
    144       1.14   thorpej 		mutex_exit(&sc->sc_intr_lock);
    145       1.14   thorpej 	}
    146       1.14   thorpej }
    147       1.14   thorpej 
    148       1.14   thorpej static void
    149       1.14   thorpej bsciic_txfill(struct bsciic_softc * const sc)
    150        1.1  jakllsch {
    151       1.14   thorpej 	uint32_t s;
    152        1.1  jakllsch 
    153       1.14   thorpej 	while (sc->sc_bufpos != sc->sc_buflen) {
    154       1.14   thorpej 		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
    155       1.14   thorpej 		if ((s & BSC_S_TXD) == 0)
    156       1.14   thorpej 			break;
    157       1.14   thorpej 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO,
    158       1.14   thorpej 		    sc->sc_buf[sc->sc_bufpos++]);
    159       1.14   thorpej 	}
    160       1.14   thorpej }
    161       1.12   thorpej 
    162       1.14   thorpej static void
    163       1.14   thorpej bsciic_rxdrain(struct bsciic_softc * const sc)
    164       1.14   thorpej {
    165       1.14   thorpej 	uint32_t s;
    166        1.1  jakllsch 
    167       1.14   thorpej 	while (sc->sc_bufpos != sc->sc_buflen) {
    168       1.14   thorpej 		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
    169       1.14   thorpej 		if ((s & BSC_S_RXD) == 0)
    170       1.14   thorpej 			break;
    171       1.14   thorpej 		sc->sc_buf[sc->sc_bufpos++] =
    172       1.14   thorpej 		    (uint8_t)bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_FIFO);
    173       1.14   thorpej 	}
    174       1.14   thorpej }
    175        1.1  jakllsch 
    176       1.14   thorpej static bsc_exec_state_t
    177       1.14   thorpej bsciic_next_state(struct bsciic_softc * const sc)
    178       1.14   thorpej {
    179       1.14   thorpej 	switch (sc->sc_exec_state) {
    180       1.14   thorpej 	case BSC_EXEC_STATE_IDLE:
    181       1.14   thorpej 		if (sc->sc_exec.addr > 0x7f) {
    182       1.14   thorpej 			return BSC_EXEC_STATE_SEND_ADDR;
    183       1.14   thorpej 		}
    184       1.14   thorpej 		/* FALLTHROUGH */
    185        1.1  jakllsch 
    186       1.14   thorpej 	case BSC_EXEC_STATE_SEND_ADDR:
    187       1.14   thorpej 		if (sc->sc_exec.cmdlen) {
    188       1.14   thorpej 			return BSC_EXEC_STATE_SEND_CMD;
    189       1.14   thorpej 		}
    190       1.14   thorpej 		/* FALLTHROUGH */
    191        1.1  jakllsch 
    192       1.14   thorpej 	case BSC_EXEC_STATE_SEND_CMD:
    193       1.14   thorpej 		if (sc->sc_exec.datalen == 0) {
    194       1.14   thorpej 			return BSC_EXEC_STATE_DONE;
    195        1.1  jakllsch 		}
    196       1.14   thorpej 
    197       1.14   thorpej 		if (I2C_OP_READ_P(sc->sc_exec.op)) {
    198       1.14   thorpej 			return BSC_EXEC_STATE_RECV_DATA;
    199        1.1  jakllsch 		}
    200       1.14   thorpej 
    201       1.14   thorpej 		return BSC_EXEC_STATE_SEND_DATA;
    202       1.14   thorpej 
    203       1.14   thorpej 	case BSC_EXEC_STATE_SEND_DATA:
    204       1.14   thorpej 	case BSC_EXEC_STATE_RECV_DATA:
    205       1.14   thorpej 		return BSC_EXEC_STATE_DONE;
    206  1.15.22.1     skrll 
    207       1.14   thorpej 	case BSC_EXEC_STATE_DONE:
    208       1.14   thorpej 	case BSC_EXEC_STATE_ERROR:
    209       1.14   thorpej 		return sc->sc_exec_state;
    210       1.14   thorpej 	}
    211       1.14   thorpej 
    212       1.14   thorpej 	panic("bsciic_next_state: invalid state: %d", sc->sc_exec_state);
    213       1.14   thorpej }
    214       1.14   thorpej 
    215       1.14   thorpej #define	BSC_EXEC_PHASE_COMPLETE(sc)				\
    216       1.14   thorpej 	((sc)->sc_exec_state == BSC_EXEC_STATE_ERROR ||		\
    217       1.14   thorpej 	 (sc)->sc_bufpos == (sc)->sc_buflen)
    218       1.14   thorpej 
    219       1.14   thorpej static void
    220       1.14   thorpej bsciic_signal(struct bsciic_softc * const sc)
    221       1.14   thorpej {
    222       1.14   thorpej 	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
    223       1.14   thorpej 		cv_signal(&sc->sc_intr_wait);
    224        1.1  jakllsch 	}
    225       1.14   thorpej }
    226        1.1  jakllsch 
    227       1.14   thorpej static void
    228       1.14   thorpej bsciic_phase_done(struct bsciic_softc * const sc)
    229       1.14   thorpej {
    230       1.14   thorpej 	sc->sc_exec_state = bsciic_next_state(sc);
    231       1.14   thorpej 	(*bsciic_exec_state_data[sc->sc_exec_state].func)(sc);
    232       1.14   thorpej }
    233       1.14   thorpej 
    234       1.14   thorpej static void
    235       1.14   thorpej bsciic_abort(struct bsciic_softc * const sc)
    236       1.14   thorpej {
    237       1.14   thorpej 	sc->sc_exec_state = BSC_EXEC_STATE_ERROR;
    238       1.14   thorpej 	bsciic_phase_done(sc);
    239       1.14   thorpej }
    240       1.14   thorpej 
    241       1.15  jmcneill int
    242       1.14   thorpej bsciic_intr(void *v)
    243       1.14   thorpej {
    244       1.14   thorpej 	struct bsciic_softc * const sc = v;
    245       1.14   thorpej 	uint32_t s;
    246       1.14   thorpej 
    247       1.14   thorpej 	bsciic_exec_lock(sc);
    248       1.14   thorpej 
    249       1.14   thorpej 	if ((sc->sc_exec.flags & I2C_F_POLL) == 0 &&
    250       1.14   thorpej 	    sc->sc_expecting_interrupt == false) {
    251       1.14   thorpej 		bsciic_exec_unlock(sc);
    252       1.14   thorpej 		return 0;
    253       1.14   thorpej 	}
    254        1.1  jakllsch 
    255        1.1  jakllsch 	s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
    256       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S,
    257       1.14   thorpej 	    BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
    258       1.14   thorpej 
    259       1.14   thorpej 	if (s & (BSC_S_CLKT | BSC_S_ERR)) {
    260       1.14   thorpej 		/*
    261       1.14   thorpej 		 * ERR might be a normal "probing for device" sort
    262       1.14   thorpej 		 * of thing, so don't complain about that one.
    263       1.14   thorpej 		 * Do complain about CLKT, though.
    264       1.14   thorpej 		 */
    265       1.14   thorpej 		if ((s & BSC_S_CLKT) ||
    266       1.14   thorpej 		    (bsciic_debug && (s & BSC_S_ERR))) {
    267       1.14   thorpej 			device_printf(sc->sc_dev,
    268       1.14   thorpej 			    "error s=0x%08x, aborting transfer\n", s);
    269       1.14   thorpej 		}
    270       1.14   thorpej 		bsciic_abort(sc);
    271       1.14   thorpej 		goto out;
    272       1.14   thorpej 	}
    273        1.1  jakllsch 
    274       1.14   thorpej 	if (BSC_EXEC_STATE_SENDING(sc)) {
    275       1.14   thorpej 		/*
    276       1.14   thorpej 		 * When transmitting, we need to wait for one final
    277       1.14   thorpej 		 * interrupt after pushing out the last of our data.
    278       1.14   thorpej 		 * Catch that case here and go to the next state.
    279       1.14   thorpej 		 */
    280       1.14   thorpej 		if (BSC_EXEC_PHASE_COMPLETE(sc)) {
    281       1.14   thorpej 			bsciic_phase_done(sc);
    282       1.14   thorpej 		} else {
    283       1.14   thorpej 			bsciic_txfill(sc);
    284       1.14   thorpej 		}
    285       1.14   thorpej 	} else if (BSC_EXEC_STATE_RECEIVING(sc)) {
    286       1.14   thorpej 		bsciic_rxdrain(sc);
    287       1.14   thorpej 		/*
    288       1.14   thorpej 		 * If we've received all of the data, go to the next
    289       1.14   thorpej 		 * state now; we might not get another interrupt.
    290       1.14   thorpej 		 */
    291       1.14   thorpej 		if (BSC_EXEC_PHASE_COMPLETE(sc)) {
    292       1.14   thorpej 			bsciic_phase_done(sc);
    293       1.14   thorpej 		}
    294       1.14   thorpej 	} else {
    295       1.14   thorpej 		device_printf(sc->sc_dev,
    296       1.14   thorpej 		    "unexpected interrupt: state=%d s=0x%08x\n",
    297       1.14   thorpej 		    sc->sc_exec_state, s);
    298       1.14   thorpej 		bsciic_abort(sc);
    299       1.14   thorpej 	}
    300        1.4  jakllsch 
    301       1.14   thorpej  out:
    302       1.14   thorpej 	bsciic_exec_unlock(sc);
    303       1.14   thorpej 	return (1);
    304       1.14   thorpej }
    305        1.1  jakllsch 
    306       1.14   thorpej static void
    307       1.14   thorpej bsciic_wait(struct bsciic_softc * const sc, const uint32_t events)
    308       1.14   thorpej {
    309       1.14   thorpej 	if ((sc->sc_exec.flags & I2C_F_POLL) == 0) {
    310       1.14   thorpej 		return;
    311       1.14   thorpej 	}
    312        1.1  jakllsch 
    313       1.14   thorpej 	const uint32_t s_bits =
    314       1.14   thorpej 	    events | BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE;
    315       1.14   thorpej 	uint32_t s;
    316        1.1  jakllsch 
    317       1.14   thorpej 	/* sc_intr_lock is not held in this case. */
    318        1.1  jakllsch 
    319       1.14   thorpej 	for (;;) {
    320        1.1  jakllsch 		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
    321       1.14   thorpej 		if (s & s_bits) {
    322       1.14   thorpej 			(void) bsciic_intr(sc);
    323       1.14   thorpej 		}
    324       1.14   thorpej 		if (BSC_EXEC_PHASE_COMPLETE(sc)) {
    325       1.14   thorpej 			bsciic_phase_done(sc);
    326        1.1  jakllsch 		}
    327       1.14   thorpej 		if (sc->sc_exec_state >= BSC_EXEC_STATE_DONE) {
    328       1.14   thorpej 			return;
    329        1.1  jakllsch 		}
    330       1.14   thorpej 		delay(1);
    331       1.14   thorpej 	}
    332       1.14   thorpej }
    333       1.14   thorpej 
    334       1.14   thorpej static void
    335       1.14   thorpej bsciic_start(struct bsciic_softc * const sc)
    336       1.14   thorpej {
    337       1.14   thorpej 
    338       1.14   thorpej 	sc->sc_c_bits = BSC_C_I2CEN | BSC_C_INTD |
    339       1.14   thorpej 	    bsciic_exec_state_data[sc->sc_exec_state].c_bits;
    340       1.14   thorpej 
    341       1.14   thorpej 	/* Clear the interrupt-enable bits if we're polling. */
    342       1.14   thorpej 	if (sc->sc_exec.flags & I2C_F_POLL) {
    343       1.14   thorpej 		sc->sc_c_bits &= ~(BSC_C_INTD | BSC_C_INTT | BSC_C_INTR);
    344       1.14   thorpej 	}
    345       1.14   thorpej 
    346       1.14   thorpej 	sc->sc_expecting_interrupt =
    347       1.14   thorpej 	    (sc->sc_c_bits & (BSC_C_INTD | BSC_C_INTT | BSC_C_INTR)) ? true
    348       1.14   thorpej 								     : false;
    349       1.14   thorpej 
    350       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C,
    351       1.14   thorpej 	    sc->sc_c_bits | BSC_C_ST);
    352       1.14   thorpej 	bsciic_wait(sc, bsciic_exec_state_data[sc->sc_exec_state].s_bits);
    353       1.14   thorpej }
    354       1.14   thorpej 
    355       1.14   thorpej static void
    356       1.14   thorpej bsciic_exec_func_idle(struct bsciic_softc * const sc)
    357       1.14   thorpej {
    358       1.14   thorpej 	/* We kick off a transfer by setting the slave address register. */
    359       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_A, sc->sc_exec.addr);
    360       1.14   thorpej 
    361       1.14   thorpej 	/* Immediately transition to the next state. */
    362       1.14   thorpej 	bsciic_phase_done(sc);
    363       1.14   thorpej }
    364       1.14   thorpej 
    365       1.14   thorpej static void
    366       1.14   thorpej bsciic_exec_func_send_addr(struct bsciic_softc * const sc)
    367       1.14   thorpej {
    368       1.14   thorpej 	/* XXX For 10-bit addressing; not implemented yet. */
    369       1.14   thorpej 	panic("bsciic_exec_func_send_addr is not supposed to be called");
    370       1.14   thorpej }
    371       1.14   thorpej 
    372       1.14   thorpej static void
    373       1.14   thorpej bsciic_exec_func_send_cmd(struct bsciic_softc * const sc)
    374       1.14   thorpej {
    375       1.14   thorpej 	sc->sc_buf = __UNCONST(sc->sc_exec.cmdbuf);
    376       1.14   thorpej 	sc->sc_bufpos = 0;
    377       1.14   thorpej 	sc->sc_buflen = sc->sc_exec.cmdlen;
    378       1.14   thorpej 
    379       1.14   thorpej 	uint32_t dlen = sc->sc_exec.cmdlen;
    380       1.14   thorpej 	if (! I2C_OP_READ_P(sc->sc_exec.op)) {
    381       1.14   thorpej 		dlen += sc->sc_exec.datalen;
    382        1.1  jakllsch 	}
    383       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
    384       1.14   thorpej 
    385       1.14   thorpej 	bsciic_start(sc);
    386       1.14   thorpej }
    387        1.1  jakllsch 
    388       1.14   thorpej static void
    389       1.14   thorpej bsciic_exec_func_send_data(struct bsciic_softc * const sc)
    390       1.14   thorpej {
    391       1.14   thorpej 	sc->sc_buf = sc->sc_exec.databuf;
    392       1.14   thorpej 	sc->sc_bufpos = 0;
    393       1.14   thorpej 	sc->sc_buflen = sc->sc_exec.datalen;
    394       1.14   thorpej 
    395       1.14   thorpej 	if (sc->sc_exec.cmdlen) {
    396       1.14   thorpej 		/*
    397       1.14   thorpej 		 * Output has already been started in this case; we just
    398       1.14   thorpej 		 * needed to switch buffers.
    399       1.14   thorpej 		 */
    400       1.14   thorpej 		bsciic_wait(sc, BSC_S_TXW);
    401       1.14   thorpej 	} else {
    402       1.14   thorpej 		uint32_t dlen = sc->sc_exec.datalen;
    403       1.14   thorpej 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
    404       1.14   thorpej 		bsciic_start(sc);
    405       1.14   thorpej 	}
    406       1.14   thorpej }
    407        1.1  jakllsch 
    408       1.14   thorpej static void
    409       1.14   thorpej bsciic_exec_func_recv_data(struct bsciic_softc * const sc)
    410       1.14   thorpej {
    411       1.14   thorpej 	sc->sc_buf = sc->sc_exec.databuf;
    412       1.14   thorpej 	sc->sc_bufpos = 0;
    413       1.14   thorpej 	sc->sc_buflen = sc->sc_exec.datalen;
    414        1.1  jakllsch 
    415       1.14   thorpej 	uint32_t dlen = sc->sc_exec.datalen;
    416       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, dlen);
    417        1.1  jakllsch 
    418       1.14   thorpej 	bsciic_start(sc);
    419       1.14   thorpej }
    420        1.1  jakllsch 
    421       1.14   thorpej static void
    422       1.14   thorpej bsciic_exec_func_done(struct bsciic_softc * const sc)
    423       1.14   thorpej {
    424       1.14   thorpej 	/* We're done!  Disable interrupts. */
    425       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C, BSC_C_I2CEN);
    426       1.14   thorpej 	sc->sc_expecting_interrupt = false;
    427       1.14   thorpej 	bsciic_signal(sc);
    428       1.14   thorpej }
    429        1.1  jakllsch 
    430       1.14   thorpej static void
    431       1.14   thorpej bsciic_exec_func_error(struct bsciic_softc * const sc)
    432       1.14   thorpej {
    433       1.14   thorpej 	/* Clear the FIFO and disable interrupts. */
    434       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C,
    435       1.14   thorpej 	    BSC_C_I2CEN | BSC_C_CLEAR_CLEAR);
    436       1.14   thorpej 	sc->sc_expecting_interrupt = false;
    437       1.14   thorpej 	bsciic_signal(sc);
    438       1.14   thorpej }
    439        1.1  jakllsch 
    440       1.15  jmcneill int
    441       1.14   thorpej bsciic_exec(void *v, i2c_op_t op, i2c_addr_t addr, const void *cmdbuf,
    442       1.14   thorpej     size_t cmdlen, void *databuf, size_t datalen, int flags)
    443       1.14   thorpej {
    444       1.14   thorpej 	struct bsciic_softc * const sc = v;
    445        1.1  jakllsch 
    446       1.14   thorpej 	/* XXX We don't do 10-bit addressing correctly yet. */
    447       1.14   thorpej 	if (addr > 0x7f)
    448       1.14   thorpej 		return (ENOTSUP);
    449        1.1  jakllsch 
    450       1.14   thorpej 	/*
    451       1.14   thorpej 	 * The I2C middle layer has ensured that the client device has
    452       1.14   thorpej 	 * exclusive access to the controller.  Copy the parameters
    453       1.14   thorpej 	 * and start the state machine that runs through the necessary
    454       1.14   thorpej 	 * phases of the request.
    455       1.14   thorpej 	 */
    456       1.14   thorpej 	KASSERT(sc->sc_exec_state == BSC_EXEC_STATE_IDLE);
    457       1.14   thorpej 	sc->sc_exec.op = op;
    458       1.14   thorpej 	sc->sc_exec.addr = addr;
    459       1.14   thorpej 	sc->sc_exec.cmdbuf = cmdbuf;
    460       1.14   thorpej 	sc->sc_exec.cmdlen = cmdlen;
    461       1.14   thorpej 	sc->sc_exec.databuf = databuf;
    462       1.14   thorpej 	sc->sc_exec.datalen = datalen;
    463       1.14   thorpej 	sc->sc_exec.flags = flags;
    464       1.14   thorpej 
    465       1.14   thorpej 	bsciic_exec_lock(sc);
    466       1.14   thorpej 	(*bsciic_exec_state_data[sc->sc_exec_state].func)(sc);
    467       1.14   thorpej 	while (sc->sc_exec_state < BSC_EXEC_STATE_DONE) {
    468       1.14   thorpej 		KASSERT((flags & I2C_F_POLL) == 0);
    469       1.14   thorpej 		cv_wait(&sc->sc_intr_wait, &sc->sc_intr_lock);
    470       1.14   thorpej 	}
    471       1.14   thorpej 	int error = sc->sc_exec_state == BSC_EXEC_STATE_ERROR ? EIO : 0;
    472       1.14   thorpej 	uint32_t s;
    473       1.14   thorpej 	do {
    474       1.14   thorpej 		s = bus_space_read_4(sc->sc_iot, sc->sc_ioh, BSC_S);
    475       1.14   thorpej 	} while ((s & BSC_S_TA) != 0);
    476       1.14   thorpej 	if (s & (BSC_S_CLKT | BSC_S_ERR)) {
    477        1.4  jakllsch 		error = EIO;
    478       1.14   thorpej 	}
    479       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_C,
    480       1.14   thorpej 	    BSC_C_I2CEN | BSC_C_CLEAR_CLEAR);
    481       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_S,
    482       1.14   thorpej 	    BSC_S_CLKT | BSC_S_ERR | BSC_S_DONE);
    483       1.14   thorpej 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, BSC_DLEN, 0);
    484       1.14   thorpej 	bsciic_exec_unlock(sc);
    485       1.14   thorpej 
    486       1.14   thorpej 	sc->sc_exec.flags = 0;
    487       1.14   thorpej 	sc->sc_exec_state = BSC_EXEC_STATE_IDLE;
    488       1.14   thorpej 	memset(&sc->sc_exec, 0, sizeof(sc->sc_exec));
    489        1.4  jakllsch 
    490        1.1  jakllsch 	return error;
    491        1.1  jakllsch }
    492