static irqreturn_t npcm_i2c_int_slave_handler()

in busses/i2c-npcm7xx.c [1038:1235]


static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus)
{
	u8 val;
	irqreturn_t ret = IRQ_NONE;
	u8 i2cst = ioread8(bus->reg + NPCM_I2CST);

	/* Slave: A NACK has occurred */
	if (NPCM_I2CST_NEGACK & i2cst) {
		bus->stop_ind = I2C_NACK_IND;
		npcm_i2c_slave_wr_buf_sync(bus);
		if (bus->fifo_use)
			/* clear the FIFO */
			iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO,
				 bus->reg + NPCM_I2CFIF_CTS);

		/* In slave write, NACK is OK, otherwise it is a problem */
		bus->stop_ind = I2C_NO_STATUS_IND;
		bus->operation = I2C_NO_OPER;
		bus->own_slave_addr = 0xFF;

		/*
		 * Slave has to wait for STOP to decide this is the end
		 * of the transaction. tx is not yet considered as done
		 */
		iowrite8(NPCM_I2CST_NEGACK, bus->reg + NPCM_I2CST);

		ret = IRQ_HANDLED;
	}

	/* Slave mode: a Bus Error (BER) has been identified */
	if (NPCM_I2CST_BER & i2cst) {
		/*
		 * Check whether bus arbitration or Start or Stop during data
		 * xfer bus arbitration problem should not result in recovery
		 */
		bus->stop_ind = I2C_BUS_ERR_IND;

		/* wait for bus busy before clear fifo */
		iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS);

		bus->state = I2C_IDLE;

		/*
		 * in BER case we might get 2 interrupts: one for slave one for
		 * master ( for a channel which is master\slave switching)
		 */
		if (completion_done(&bus->cmd_complete) == false) {
			bus->cmd_err = -EIO;
			complete(&bus->cmd_complete);
		}
		bus->own_slave_addr = 0xFF;
		iowrite8(NPCM_I2CST_BER, bus->reg + NPCM_I2CST);
		ret = IRQ_HANDLED;
	}

	/* A Slave Stop Condition has been identified */
	if (NPCM_I2CST_SLVSTP & i2cst) {
		u8 bytes_in_fifo = npcm_i2c_fifo_usage(bus);

		bus->stop_ind = I2C_SLAVE_DONE_IND;

		if (bus->operation == I2C_READ_OPER)
			npcm_i2c_read_fifo_slave(bus, bytes_in_fifo);

		/* if the buffer is empty nothing will be sent */
		npcm_i2c_slave_send_rd_buf(bus);

		/* Slave done transmitting or receiving */
		bus->stop_ind = I2C_NO_STATUS_IND;

		/*
		 * Note, just because we got here, it doesn't mean we through
		 * away the wr buffer.
		 * we keep it until the next received offset.
		 */
		bus->operation = I2C_NO_OPER;
		bus->own_slave_addr = 0xFF;
		i2c_slave_event(bus->slave, I2C_SLAVE_STOP, 0);
		iowrite8(NPCM_I2CST_SLVSTP, bus->reg + NPCM_I2CST);
		if (bus->fifo_use) {
			npcm_i2c_clear_fifo_int(bus);
			npcm_i2c_clear_rx_fifo(bus);
			npcm_i2c_clear_tx_fifo(bus);

			iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO,
				 bus->reg + NPCM_I2CFIF_CTS);
		}
		bus->state = I2C_IDLE;
		ret = IRQ_HANDLED;
	}

	/* restart condition occurred and Rx-FIFO was not empty */
	if (bus->fifo_use && FIELD_GET(NPCM_I2CFIF_CTS_SLVRSTR,
				       ioread8(bus->reg + NPCM_I2CFIF_CTS))) {
		bus->stop_ind = I2C_SLAVE_RESTART_IND;
		bus->master_or_slave = I2C_SLAVE;
		if (bus->operation == I2C_READ_OPER)
			npcm_i2c_read_fifo_slave(bus, npcm_i2c_fifo_usage(bus));
		bus->operation = I2C_WRITE_OPER;
		iowrite8(0, bus->reg + NPCM_I2CRXF_CTL);
		val = NPCM_I2CFIF_CTS_CLR_FIFO | NPCM_I2CFIF_CTS_SLVRSTR |
		      NPCM_I2CFIF_CTS_RXF_TXE;
		iowrite8(val, bus->reg + NPCM_I2CFIF_CTS);
		npcm_i2c_slave_rd_wr(bus);
		ret = IRQ_HANDLED;
	}

	/* A Slave Address Match has been identified */
	if (NPCM_I2CST_NMATCH & i2cst) {
		u8 info = 0;

		/* Address match automatically implies slave mode */
		bus->master_or_slave = I2C_SLAVE;
		npcm_i2c_clear_fifo_int(bus);
		npcm_i2c_clear_rx_fifo(bus);
		npcm_i2c_clear_tx_fifo(bus);
		iowrite8(0, bus->reg + NPCM_I2CTXF_CTL);
		iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL);
		if (NPCM_I2CST_XMIT & i2cst) {
			bus->operation = I2C_WRITE_OPER;
		} else {
			i2c_slave_event(bus->slave, I2C_SLAVE_WRITE_REQUESTED,
					&info);
			bus->operation = I2C_READ_OPER;
		}
		if (bus->own_slave_addr == 0xFF) {
			/* Check which type of address match */
			val = ioread8(bus->reg + NPCM_I2CCST);
			if (NPCM_I2CCST_MATCH & val) {
				u16 addr;
				enum i2c_addr eaddr;
				u8 i2ccst2;
				u8 i2ccst3;

				i2ccst3 = ioread8(bus->reg + NPCM_I2CCST3);
				i2ccst2 = ioread8(bus->reg + NPCM_I2CCST2);

				/*
				 * the i2c module can response to 10 own SA.
				 * check which one was addressed by the master.
				 * repond to the first one.
				 */
				addr = ((i2ccst3 & 0x07) << 7) |
					(i2ccst2 & 0x7F);
				info = ffs(addr);
				eaddr = (enum i2c_addr)info;
				addr = npcm_i2c_get_slave_addr(bus, eaddr);
				addr &= 0x7F;
				bus->own_slave_addr = addr;
				if (bus->PEC_mask & BIT(info))
					bus->PEC_use = true;
				else
					bus->PEC_use = false;
			} else {
				if (NPCM_I2CCST_GCMATCH & val)
					bus->own_slave_addr = 0;
				if (NPCM_I2CCST_ARPMATCH & val)
					bus->own_slave_addr = 0x61;
			}
		} else {
			/*
			 *  Slave match can happen in two options:
			 *  1. Start, SA, read (slave read without further ado)
			 *  2. Start, SA, read, data, restart, SA, read,  ...
			 *     (slave read in fragmented mode)
			 *  3. Start, SA, write, data, restart, SA, read, ..
			 *     (regular write-read mode)
			 */
			if ((bus->state == I2C_OPER_STARTED &&
			     bus->operation == I2C_READ_OPER &&
			     bus->stop_ind == I2C_SLAVE_XMIT_IND) ||
			     bus->stop_ind == I2C_SLAVE_RCV_IND) {
				/* slave tx after slave rx w/o STOP */
				bus->stop_ind = I2C_SLAVE_RESTART_IND;
			}
		}

		if (NPCM_I2CST_XMIT & i2cst)
			bus->stop_ind = I2C_SLAVE_XMIT_IND;
		else
			bus->stop_ind = I2C_SLAVE_RCV_IND;
		bus->state = I2C_SLAVE_MATCH;
		npcm_i2c_slave_rd_wr(bus);
		iowrite8(NPCM_I2CST_NMATCH, bus->reg + NPCM_I2CST);
		ret = IRQ_HANDLED;
	}

	/* Slave SDA status is set - tx or rx */
	if ((NPCM_I2CST_SDAST & i2cst) ||
	    (bus->fifo_use &&
	    (npcm_i2c_tx_fifo_empty(bus) || npcm_i2c_rx_fifo_full(bus)))) {
		npcm_i2c_slave_rd_wr(bus);
		iowrite8(NPCM_I2CST_SDAST, bus->reg + NPCM_I2CST);
		ret = IRQ_HANDLED;
	} /* SDAST */

	return ret;
}