コード例 #1
0
ファイル: bcm2835_bsc.c プロジェクト: cyrilmagsuci/freebsd
static int
bcm_bsc_rise_proc(SYSCTL_HANDLER_ARGS)
{
    struct bcm_bsc_softc *sc;
    uint32_t clk, reg;
    int error;

    sc = (struct bcm_bsc_softc *)arg1;

    BCM_BSC_LOCK(sc);
    reg = BCM_BSC_READ(sc, BCM_BSC_DELAY);
    BCM_BSC_UNLOCK(sc);
    reg &= 0xffff;
    error = sysctl_handle_int(oidp, &reg, sizeof(reg), req);
    if (error != 0 || req->newptr == NULL)
        return (error);

    BCM_BSC_LOCK(sc);
    clk = BCM_BSC_READ(sc, BCM_BSC_CLOCK);
    clk = BCM_BSC_CORE_CLK / clk;
    if (reg > clk / 2)
        reg = clk / 2 - 1;
    bcm_bsc_modifyreg(sc, BCM_BSC_DELAY, 0xffff, reg);
    BCM_BSC_UNLOCK(sc);

    return (0);
}
コード例 #2
0
ファイル: bcm2835_bsc.c プロジェクト: MattDooner/freebsd-west
static void
bcm_bsc_intr(void *arg)
{
	struct bcm_bsc_softc *sc;
	uint32_t status;

	sc = (struct bcm_bsc_softc *)arg;

	BCM_BSC_LOCK(sc);

	/* The I2C interrupt is shared among all the BSC controllers. */
	if ((sc->sc_flags & BCM_I2C_BUSY) == 0) {
		BCM_BSC_UNLOCK(sc);
		return;
	}

	status = BCM_BSC_READ(sc, BCM_BSC_STATUS);

	/* Check for errors. */
	if (status & (BCM_BSC_STATUS_CLKT | BCM_BSC_STATUS_ERR)) {
		/* Disable interrupts. */
		BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
		sc->sc_flags |= BCM_I2C_ERROR;
		bcm_bsc_reset(sc);
		wakeup(sc->sc_dev);
		BCM_BSC_UNLOCK(sc);
		return;
	}

	if (sc->sc_flags & BCM_I2C_READ) {
		while (sc->sc_resid > 0 && (status & BCM_BSC_STATUS_RXD)) {
			*sc->sc_data++ = BCM_BSC_READ(sc, BCM_BSC_DATA);
			sc->sc_resid--;
			status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
		}
	} else {
		while (sc->sc_resid > 0 && (status & BCM_BSC_STATUS_TXD)) {
			BCM_BSC_WRITE(sc, BCM_BSC_DATA, *sc->sc_data++);
			sc->sc_resid--;
			status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
		}
	}

	if (status & BCM_BSC_STATUS_DONE) {
		/* Disable interrupts. */
		BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN);
		bcm_bsc_reset(sc);
		wakeup(sc->sc_dev);
	}

	BCM_BSC_UNLOCK(sc);
}
コード例 #3
0
ファイル: bcm2835_bsc.c プロジェクト: Lxg1582/freebsd
static int
bcm_bsc_clock_proc(SYSCTL_HANDLER_ARGS)
{
	struct bcm_bsc_softc *sc;
	uint32_t clk;
	int error;

	sc = (struct bcm_bsc_softc *)arg1;

	BCM_BSC_LOCK(sc);
	clk = BCM_BSC_READ(sc, BCM_BSC_CLOCK);
	BCM_BSC_UNLOCK(sc);
	clk &= 0xffff;
	if (clk == 0)
		clk = 32768;
	clk = BCM_BSC_CORE_CLK / clk;
	error = sysctl_handle_int(oidp, &clk, sizeof(clk), req);
	if (error != 0 || req->newptr == NULL)
		return (error);

	clk = BCM_BSC_CORE_CLK / clk;
	if (clk % 2)
		clk--;
	if (clk > 0xffff)
		clk = 0xffff;
	BCM_BSC_LOCK(sc);
	BCM_BSC_WRITE(sc, BCM_BSC_CLOCK, clk);
	BCM_BSC_UNLOCK(sc);

	return (0);
}
コード例 #4
0
ファイル: bcm2835_bsc.c プロジェクト: cyrilmagsuci/freebsd
static void
bcm_bsc_modifyreg(struct bcm_bsc_softc *sc, uint32_t off, uint32_t mask,
                  uint32_t value)
{
    uint32_t reg;

    mtx_assert(&sc->sc_mtx, MA_OWNED);
    reg = BCM_BSC_READ(sc, off);
    reg &= ~mask;
    reg |= value;
    BCM_BSC_WRITE(sc, off, reg);
}
コード例 #5
0
ファイル: bcm2835_bsc.c プロジェクト: cyrilmagsuci/freebsd
static int
bcm_bsc_clock_proc(SYSCTL_HANDLER_ARGS)
{
    struct bcm_bsc_softc *sc;
    uint32_t clk;

    sc = (struct bcm_bsc_softc *)arg1;
    BCM_BSC_LOCK(sc);
    clk = BCM_BSC_READ(sc, BCM_BSC_CLOCK);
    BCM_BSC_UNLOCK(sc);
    clk &= 0xffff;
    if (clk == 0)
        clk = 32768;
    clk = BCM_BSC_CORE_CLK / clk;

    return (sysctl_handle_int(oidp, &clk, 0, req));
}
コード例 #6
0
ファイル: bcm2835_bsc.c プロジェクト: cyrilmagsuci/freebsd
static int
bcm_bsc_clkt_proc(SYSCTL_HANDLER_ARGS)
{
    struct bcm_bsc_softc *sc;
    uint32_t clkt;
    int error;

    sc = (struct bcm_bsc_softc *)arg1;

    BCM_BSC_LOCK(sc);
    clkt = BCM_BSC_READ(sc, BCM_BSC_CLKT);
    BCM_BSC_UNLOCK(sc);
    clkt &= 0xffff;
    error = sysctl_handle_int(oidp, &clkt, sizeof(clkt), req);
    if (error != 0 || req->newptr == NULL)
        return (error);

    BCM_BSC_LOCK(sc);
    BCM_BSC_WRITE(sc, BCM_BSC_CLKT, clkt & 0xffff);
    BCM_BSC_UNLOCK(sc);

    return (0);
}
コード例 #7
0
ファイル: bcm2835_bsc.c プロジェクト: cyrilmagsuci/freebsd
static int
bcm_bsc_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
{
    struct bcm_bsc_softc *sc;
    uint32_t intr, read, status;
    int i, err;

    sc = device_get_softc(dev);
    BCM_BSC_LOCK(sc);

    /* If the controller is busy wait until it is available. */
    while (sc->sc_flags & BCM_I2C_BUSY)
        mtx_sleep(dev, &sc->sc_mtx, 0, "bscbusw", 0);

    /* Now we have control over the BSC controller. */
    sc->sc_flags = BCM_I2C_BUSY;

    /* Clear the FIFO and the pending interrupts. */
    bcm_bsc_reset(sc);

    err = 0;
    for (i = 0; i < nmsgs; i++) {

        /* Write the slave address. */
        BCM_BSC_WRITE(sc, BCM_BSC_SLAVE, msgs[i].slave >> 1);

        /* Write the data length. */
        BCM_BSC_WRITE(sc, BCM_BSC_DLEN, msgs[i].len);

        sc->sc_data = msgs[i].buf;
        sc->sc_resid = msgs[i].len;
        if ((msgs[i].flags & IIC_M_RD) == 0) {
            /* Fill up the TX FIFO. */
            status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
            while (sc->sc_resid > 0 &&
                    (status & BCM_BSC_STATUS_TXD)) {
                BCM_BSC_WRITE(sc, BCM_BSC_DATA, *sc->sc_data);
                sc->sc_data++;
                sc->sc_resid--;
                status = BCM_BSC_READ(sc, BCM_BSC_STATUS);
            }
            read = 0;
            intr = BCM_BSC_CTRL_INTT;
            sc->sc_flags &= ~BCM_I2C_READ;
        } else {
            sc->sc_flags |= BCM_I2C_READ;
            read = BCM_BSC_CTRL_READ;
            intr = BCM_BSC_CTRL_INTR;
        }
        intr |= BCM_BSC_CTRL_INTD;

        /* Start the transfer. */
        BCM_BSC_WRITE(sc, BCM_BSC_CTRL, BCM_BSC_CTRL_I2CEN |
                      BCM_BSC_CTRL_ST | read | intr);

        /* Wait for the transaction to complete. */
        err = mtx_sleep(dev, &sc->sc_mtx, 0, "bsciow", hz);

        /* Check for errors. */
        if (err == 0 && (sc->sc_flags & BCM_I2C_ERROR))
            err = EIO;
        if (err != 0)
            break;
    }

    /* Clean the controller flags. */
    sc->sc_flags = 0;

    /* Wake up the threads waiting for bus. */
    wakeup(dev);

    BCM_BSC_UNLOCK(sc);

    return (err);
}