Exemplo n.º 1
0
int
pcf_start(device_t dev, u_char slave, int timeout)
{
	struct pcf_softc *sc = DEVTOSOFTC(dev);
	int error = 0;

	PCF_LOCK(sc);
#ifdef PCFDEBUG
	device_printf(dev, " >> start for slave %#x\n", (unsigned)slave);
#endif
	if ((pcf_get_S1(sc) & nBB) == 0) {
#ifdef PCFDEBUG
		printf("pcf: busy!\n");
#endif
		PCF_UNLOCK(sc);
		return (IIC_EBUSBSY);
	}

	/* set slave address to PCF. Last bit (LSB) must be set correctly
	 * according to transfer direction */
	pcf_set_S0(sc, slave);

	/* START only */
	pcf_set_S1(sc, PIN|ESO|STA|ACK);

	sc->pcf_started = 1;

	/* wait for address sent, polling */
	if ((error = pcf_wait_byte(sc)))
		goto error;

	/* check for ACK */
	if (pcf_noack(sc, timeout)) {
		error = IIC_ENOACK;
#ifdef PCFDEBUG
		printf("pcf: no ack on start!\n");
#endif
		goto error;
	}

	PCF_UNLOCK(sc);
	return (0);

error:
	pcf_stop_locked(sc);
	PCF_UNLOCK(sc);
	return (error);
}
Exemplo n.º 2
0
static int
pcf_noack(struct pcf_softc *sc, int timeout)
{
	int noack;
	int k = timeout/10;

	PCF_ASSERT_LOCKED(sc);
	do {
		noack = pcf_get_S1(sc) & LRB;
		if (!noack)
			break;
		DELAY(10);				/* XXX wait 10 us */
	} while (k--);

	return (noack);
}
Exemplo n.º 3
0
Arquivo: pcf.c Projeto: MarginC/kame
/*
 * Polling mode for master operations wait for a new
 * byte incomming or outgoing
 */
int
pcf_wait_byte(struct pcf_softc *sc)
{
	int counter = TIMEOUT;

	while (counter--) {

		if ((pcf_get_S1(sc) & PIN) == 0)
			return (0);
	}

#ifdef PCFDEBUG
	printf("pcf: timeout!\n");
#endif

	return (IIC_ETIMEOUT);
}
Exemplo n.º 4
0
void
pcf_intr(void *arg)
{
	struct pcf_softc *sc = arg;
	char data, status, addr;
	char error = 0;

	PCF_LOCK(sc);
	status = pcf_get_S1(sc);

	if (status & PIN) {
		printf("pcf: spurious interrupt, status=0x%x\n",
		       status & 0xff);

		goto error;
	}

	if (status & LAB)
		printf("pcf: bus arbitration lost!\n");

	if (status & BER) {
		error = IIC_EBUSERR;
		iicbus_intr(sc->iicbus, INTR_ERROR, &error);

		goto error;
	}

	do {
		status = pcf_get_S1(sc);

		switch(sc->pcf_slave_mode) {

		case SLAVE_TRANSMITTER:
			if (status & LRB) {
				/* ack interrupt line */
				dummy_write(sc);

				/* no ack, don't send anymore */
				sc->pcf_slave_mode = SLAVE_RECEIVER;

				iicbus_intr(sc->iicbus, INTR_NOACK, NULL);
				break;
			}

			/* get data from upper code */
			iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);

			pcf_set_S0(sc, data);
			break;

		case SLAVE_RECEIVER:
			if (status & AAS) {
				addr = pcf_get_S0(sc);

				if (status & AD0)
					iicbus_intr(sc->iicbus, INTR_GENERAL, &addr);
				else
					iicbus_intr(sc->iicbus, INTR_START, &addr);

				if (addr & LSB) {
					sc->pcf_slave_mode = SLAVE_TRANSMITTER;

					/* get the first char from upper code */
					iicbus_intr(sc->iicbus, INTR_TRANSMIT, &data);

					/* send first data byte */
					pcf_set_S0(sc, data);
				}

				break;
			}

			/* stop condition received? */
			if (status & STS) {
				/* ack interrupt line */
				dummy_read(sc);

				/* emulate intr stop condition */
				iicbus_intr(sc->iicbus, INTR_STOP, NULL);

			} else {
				/* get data, ack interrupt line */
				data = pcf_get_S0(sc);

				/* deliver the character */
				iicbus_intr(sc->iicbus, INTR_RECEIVE, &data);
			}
			break;

		    default:
			panic("%s: unknown slave mode (%d)!", __func__,
				sc->pcf_slave_mode);
		    }

	} while ((pcf_get_S1(sc) & PIN) == 0);
	PCF_UNLOCK(sc);

	return;

error:
	/* unknown event on bus...reset PCF */
	pcf_set_S1(sc, PIN|ESO|ENI|ACK);

	sc->pcf_slave_mode = SLAVE_RECEIVER;
	PCF_UNLOCK(sc);

	return;
}