Lines Matching +full:assert +full:- +full:falling +full:- +full:edge

1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
34 * Driver for bcm2835 i2c-compatible two-wire bus, named 'BSC' on this SoC.
37 * low-level control over sending start/repeat-start/stop sequences on the bus.
39 * repeat-start, and limit the repeat-start to a read following a write on
43 * The repeat-start bug and workaround are described in a problem report at
47 * -----------------------------------------------------------------------------
48 * - See i2c.v: The I2C peripheral samples the values for rw_bit and xfer_count
49 * - in the IDLE state if start is set.
50 * -
51 * - We want to generate a ReSTART not a STOP at the end of the TX phase. In
52 * - order to do that we must ensure the state machine goes RACK1 -> RACK2 ->
53 * - SRSTRT1 (not RACK1 -> RACK2 -> SSTOP1).
54 * -
55 * - So, in the RACK2 state when (TX) xfer_count==0 we must therefore have
56 * - already set, ready to be sampled:
57 * - READ ; rw_bit <= I2CC bit 0 -- must be "read"
58 * - ST; start <= I2CC bit 7 -- must be "Go" in order to not issue STOP
59 * - DLEN; xfer_count <= I2CDLEN -- must be equal to our read amount
60 * -
61 * - The plan to do this is:
62 * - 1. Start the sub-address write, but don't let it finish
63 * - (keep xfer_count > 0)
64 * - 2. Populate READ, DLEN and ST in preparation for ReSTART read sequence
65 * - 3. Let TX finish (write the rest of the data)
66 * - 4. Read back data as it arrives
67 * -----------------------------------------------------------------------------
75 * repeat-start on the bus when the write operation finishes.
77 * XXX I suspect the controller may be able to do a repeat-start on any
78 * write->read or write->write transition, even when the slave addresses differ.
107 {"broadcom,bcm2835-bsc", 1},
108 {"brcm,bcm2708-i2c", 1},
109 {"brcm,bcm2835-i2c", 1},
114 if ((lvl) <= (sc)->sc_debug) \
115 device_printf((sc)->sc_dev, fmt, ##args)
118 if ((lvl) <= (sc)->sc_debug) \
130 mtx_assert(&sc->sc_mtx, MA_OWNED); in bcm_bsc_modifyreg()
169 if (error != 0 || req->newptr == NULL) in bcm_bsc_clkt_proc()
193 if (error != 0 || req->newptr == NULL) in bcm_bsc_fall_proc()
200 reg = clk / 2 - 1; in bcm_bsc_fall_proc()
221 if (error != 0 || req->newptr == NULL) in bcm_bsc_rise_proc()
228 reg = clk / 2 - 1; in bcm_bsc_rise_proc()
245 ctx = device_get_sysctl_ctx(sc->sc_dev); in bcm_bsc_sysctl_init()
246 tree_node = device_get_sysctl_tree(sc->sc_dev); in bcm_bsc_sysctl_init()
259 bcm_bsc_fall_proc, "IU", "I2C BUS falling edge delay"); in bcm_bsc_sysctl_init()
263 bcm_bsc_rise_proc, "IU", "I2C BUS rising edge delay"); in bcm_bsc_sysctl_init()
265 CTLFLAG_RWTUN, &sc->sc_debug, 0, in bcm_bsc_sysctl_init()
290 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) in bcm_bsc_probe()
305 sc->sc_dev = dev; in bcm_bsc_attach()
308 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, in bcm_bsc_attach()
310 if (!sc->sc_mem_res) { in bcm_bsc_attach()
315 sc->sc_bst = rman_get_bustag(sc->sc_mem_res); in bcm_bsc_attach()
316 sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); in bcm_bsc_attach()
319 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, in bcm_bsc_attach()
321 if (!sc->sc_irq_res) { in bcm_bsc_attach()
322 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); in bcm_bsc_attach()
328 if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, in bcm_bsc_attach()
329 NULL, bcm_bsc_intr, sc, &sc->sc_intrhand)) { in bcm_bsc_attach()
330 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); in bcm_bsc_attach()
331 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); in bcm_bsc_attach()
336 mtx_init(&sc->sc_mtx, "bcm_bsc", NULL, MTX_DEF); in bcm_bsc_attach()
345 sc->sc_iicbus = device_add_child(dev, "iicbus", DEVICE_UNIT_ANY); in bcm_bsc_attach()
346 if (sc->sc_iicbus == NULL) { in bcm_bsc_attach()
364 mtx_destroy(&sc->sc_mtx); in bcm_bsc_detach()
365 if (sc->sc_intrhand) in bcm_bsc_detach()
366 bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); in bcm_bsc_detach()
367 if (sc->sc_irq_res) in bcm_bsc_detach()
368 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); in bcm_bsc_detach()
369 if (sc->sc_mem_res) in bcm_bsc_detach()
370 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); in bcm_bsc_detach()
382 if (sc->sc_resid == 0) { in bcm_bsc_empty_rx_fifo()
383 sc->sc_data = sc->sc_curmsg->buf; in bcm_bsc_empty_rx_fifo()
384 sc->sc_dlen = sc->sc_curmsg->len; in bcm_bsc_empty_rx_fifo()
385 sc->sc_resid = sc->sc_dlen; in bcm_bsc_empty_rx_fifo()
386 ++sc->sc_curmsg; in bcm_bsc_empty_rx_fifo()
389 *sc->sc_data = BCM_BSC_READ(sc, BCM_BSC_DATA); in bcm_bsc_empty_rx_fifo()
390 DEBUGF(sc, 1, "0x%02x ", *sc->sc_data); in bcm_bsc_empty_rx_fifo()
391 ++sc->sc_data; in bcm_bsc_empty_rx_fifo()
392 --sc->sc_resid; in bcm_bsc_empty_rx_fifo()
393 --sc->sc_totlen; in bcm_bsc_empty_rx_fifo()
395 } while (sc->sc_resid > 0 && (status & BCM_BSC_STATUS_RXD)); in bcm_bsc_empty_rx_fifo()
396 } while (sc->sc_totlen > 0 && (status & BCM_BSC_STATUS_RXD)); in bcm_bsc_empty_rx_fifo()
406 if (sc->sc_resid == 0) { in bcm_bsc_fill_tx_fifo()
407 sc->sc_data = sc->sc_curmsg->buf; in bcm_bsc_fill_tx_fifo()
408 sc->sc_dlen = sc->sc_curmsg->len; in bcm_bsc_fill_tx_fifo()
409 sc->sc_resid = sc->sc_dlen; in bcm_bsc_fill_tx_fifo()
410 ++sc->sc_curmsg; in bcm_bsc_fill_tx_fifo()
413 BCM_BSC_WRITE(sc, BCM_BSC_DATA, *sc->sc_data); in bcm_bsc_fill_tx_fifo()
414 DEBUGF(sc, 1, "0x%02x ", *sc->sc_data); in bcm_bsc_fill_tx_fifo()
415 ++sc->sc_data; in bcm_bsc_fill_tx_fifo()
416 --sc->sc_resid; in bcm_bsc_fill_tx_fifo()
417 --sc->sc_totlen; in bcm_bsc_fill_tx_fifo()
419 } while (sc->sc_resid > 0 && (status & BCM_BSC_STATUS_TXD)); in bcm_bsc_fill_tx_fifo()
421 * If a repeat-start was pending and we just hit the end of a tx in bcm_bsc_fill_tx_fifo()
423 * the repeat-start. If so, log the repeat-start and the start in bcm_bsc_fill_tx_fifo()
428 if (sc->sc_replen > 0 && sc->sc_resid == 0) { in bcm_bsc_fill_tx_fifo()
429 sc->sc_replen -= sc->sc_dlen; in bcm_bsc_fill_tx_fifo()
430 if (sc->sc_replen == 0) { in bcm_bsc_fill_tx_fifo()
433 sc->sc_curmsg->slave | 0x01); in bcm_bsc_fill_tx_fifo()
436 sc->sc_curmsg->slave | 0x01, in bcm_bsc_fill_tx_fifo()
437 sc->sc_totlen); in bcm_bsc_fill_tx_fifo()
438 sc->sc_flags |= BCM_I2C_READ; in bcm_bsc_fill_tx_fifo()
442 } while (sc->sc_totlen > 0 && (status & BCM_BSC_STATUS_TXD)); in bcm_bsc_fill_tx_fifo()
456 if ((sc->sc_flags & BCM_I2C_BUSY) == 0) { in bcm_bsc_intr()
464 /* RXD and DONE can assert together, empty fifo before checking done. */ in bcm_bsc_intr()
465 if ((sc->sc_flags & BCM_I2C_READ) && (status & BCM_BSC_STATUS_RXD)) in bcm_bsc_intr()
470 sc->sc_flags |= BCM_I2C_DONE; in bcm_bsc_intr()
472 sc->sc_flags |= BCM_I2C_ERROR; in bcm_bsc_intr()
476 } else if (!(sc->sc_flags & BCM_I2C_READ)) { in bcm_bsc_intr()
482 if ((status & BCM_BSC_STATUS_TXD) && sc->sc_totlen > 0) in bcm_bsc_intr()
503 while (sc->sc_flags & BCM_I2C_BUSY) in bcm_bsc_transfer()
504 mtx_sleep(dev, &sc->sc_mtx, 0, "bscbusw", 0); in bcm_bsc_transfer()
507 sc->sc_flags = BCM_I2C_BUSY; in bcm_bsc_transfer()
517 * sc->sc_curmsg through the array of messages, as the data from each in bcm_bsc_transfer()
522 sc->sc_resid = 0; in bcm_bsc_transfer()
523 sc->sc_curmsg = msgs; in bcm_bsc_transfer()
525 while (sc->sc_curmsg < endmsgs) { in bcm_bsc_transfer()
527 curslave = sc->sc_curmsg->slave >> 1; in bcm_bsc_transfer()
528 curisread = sc->sc_curmsg->flags & IIC_M_RD; in bcm_bsc_transfer()
529 sc->sc_replen = 0; in bcm_bsc_transfer()
530 sc->sc_totlen = sc->sc_curmsg->len; in bcm_bsc_transfer()
533 * repeat-start (read following write for the same slave). in bcm_bsc_transfer()
535 for (nxtmsg = sc->sc_curmsg + 1; nxtmsg < endmsgs; ++nxtmsg) { in bcm_bsc_transfer()
536 nxtslave = nxtmsg->slave >> 1; in bcm_bsc_transfer()
538 nxtisread = nxtmsg->flags & IIC_M_RD; in bcm_bsc_transfer()
545 sc->sc_totlen += nxtmsg->len; in bcm_bsc_transfer()
550 * repeat-start, remember how many bytes in bcm_bsc_transfer()
551 * come before the repeat-start, switch in bcm_bsc_transfer()
556 sc->sc_replen = sc->sc_totlen; in bcm_bsc_transfer()
557 sc->sc_totlen += nxtmsg->len; in bcm_bsc_transfer()
566 * the after-repstart msg, reset them to reflect sc_curmsg. in bcm_bsc_transfer()
568 curisread = (sc->sc_curmsg->flags & IIC_M_RD) ? 1 : 0; in bcm_bsc_transfer()
569 curslave = sc->sc_curmsg->slave | curisread; in bcm_bsc_transfer()
579 * piece of a transfer that involves a repeat-start and set up in bcm_bsc_transfer()
582 if (sc->sc_replen == 0) { in bcm_bsc_transfer()
583 DEVICE_DEBUGF(sc, 1, "%-6s 0x%02x len %d: ", in bcm_bsc_transfer()
585 sc->sc_totlen); in bcm_bsc_transfer()
586 curlen = sc->sc_totlen; in bcm_bsc_transfer()
589 sc->sc_flags |= BCM_I2C_READ; in bcm_bsc_transfer()
592 sc->sc_flags &= ~BCM_I2C_READ; in bcm_bsc_transfer()
595 DEVICE_DEBUGF(sc, 1, "%-6s 0x%02x len %d: ", in bcm_bsc_transfer()
597 sc->sc_replen); in bcm_bsc_transfer()
607 BCM_BSC_WRITE(sc, BCM_BSC_DLEN, sc->sc_replen); in bcm_bsc_transfer()
619 * Set curlen and readctl for the repeat-start read that in bcm_bsc_transfer()
623 curlen = sc->sc_totlen - sc->sc_replen; in bcm_bsc_transfer()
625 sc->sc_flags &= ~BCM_I2C_READ; in bcm_bsc_transfer()
632 * repeat-start work, and it's harmless to do it in this order in bcm_bsc_transfer()
639 if (!(sc->sc_curmsg->flags & IIC_M_RD)) { in bcm_bsc_transfer()
644 while (err == 0 && !(sc->sc_flags & BCM_I2C_DONE)) { in bcm_bsc_transfer()
645 err = mtx_sleep(sc, &sc->sc_mtx, 0, "bsciow", hz); in bcm_bsc_transfer()
648 if (err == 0 && (sc->sc_flags & BCM_I2C_ERROR)) in bcm_bsc_transfer()
661 sc->sc_flags = 0; in bcm_bsc_transfer()
680 if (sc->sc_iicbus == NULL) in bcm_bsc_iicbus_reset()
683 busfreq = IICBUS_GET_FREQUENCY(sc->sc_iicbus, speed); in bcm_bsc_iicbus_reset()