Example #1
0
static int kw_handle_interrupt(struct low_i2c_host *host, int state, int rw, int *rc, u8 **data, int *len, u8 isr)
{
	u8 ack;

	if (isr == 0) {
		if (state != state_stop) {
			DBG("KW: Timeout !\n");
			*rc = -EIO;
			goto stop;
		}
		if (state == state_stop) {
			ack = kw_read_reg(reg_status);
			if (!(ack & KW_I2C_STAT_BUSY)) {
				state = state_idle;
				kw_write_reg(reg_ier, 0x00);
			}
		}
		return state;
	}

	if (isr & KW_I2C_IRQ_ADDR) {
		ack = kw_read_reg(reg_status);
		if (state != state_addr) {
			kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
			WRONG_STATE("KW_I2C_IRQ_ADDR"); 
			*rc = -EIO;
			goto stop;
		}
		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {			
			*rc = -ENODEV;
			DBG("KW: NAK on address\n");
			return state_stop;		     
		} else {
			if (rw) {
				state = state_read;
				if (*len > 1)
					kw_write_reg(reg_control, KW_I2C_CTL_AAK);
			} else {
				state = state_write;
				kw_write_reg(reg_data, **data);
				(*data)++; (*len)--;
			}
		}
		kw_write_reg(reg_isr, KW_I2C_IRQ_ADDR);
	}

	if (isr & KW_I2C_IRQ_DATA) {
		if (state == state_read) {
			**data = kw_read_reg(reg_data);
			(*data)++; (*len)--;
			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
			if ((*len) == 0)
				state = state_stop;
			else if ((*len) == 1)
				kw_write_reg(reg_control, 0);
		} else if (state == state_write) {
			ack = kw_read_reg(reg_status);
			if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
				DBG("KW: nack on data write\n");
				*rc = -EIO;
				goto stop;
			} else if (*len) {
				kw_write_reg(reg_data, **data);
				(*data)++; (*len)--;
			} else {
				kw_write_reg(reg_control, KW_I2C_CTL_STOP);
				state = state_stop;
				*rc = 0;
			}
			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
		} else {
			kw_write_reg(reg_isr, KW_I2C_IRQ_DATA);
			WRONG_STATE("KW_I2C_IRQ_DATA"); 
			if (state != state_stop) {
				*rc = -EIO;
				goto stop;
			}
		}
	}

	if (isr & KW_I2C_IRQ_STOP) {
		kw_write_reg(reg_isr, KW_I2C_IRQ_STOP);
		if (state != state_stop) {
			WRONG_STATE("KW_I2C_IRQ_STOP");
			*rc = -EIO;
		}
		return state_idle;
	}

	if (isr & KW_I2C_IRQ_START)
		kw_write_reg(reg_isr, KW_I2C_IRQ_START);

	return state;

 stop:
	kw_write_reg(reg_control, KW_I2C_CTL_STOP);	
	return state_stop;
}
Example #2
0
/* Main state machine for standard & standard sub mode */
static void
handle_interrupt(struct keywest_iface *iface, u8 isr)
{
	int ack;
	
	if (isr == 0) {
		if (iface->state != state_stop) {
			pr_debug("KW: Timeout !\n");
			do_stop(iface, -EIO);
		}
		if (iface->state == state_stop) {
			ack = read_reg(reg_status);
			if (!(ack & KW_I2C_STAT_BUSY)) {
				iface->state = state_idle;
				write_reg(reg_ier, 0x00);
#ifndef POLLED_MODE
				complete(&iface->complete);
#endif /* POLLED_MODE */
			}
		}
		return;
	}

	if (isr & KW_I2C_IRQ_ADDR) {
		ack = read_reg(reg_status);
		if (iface->state != state_addr) {
			write_reg(reg_isr, KW_I2C_IRQ_ADDR);
			WRONG_STATE("KW_I2C_IRQ_ADDR"); 
			do_stop(iface, -EIO);
			return;
		}
		if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
			iface->state = state_stop;		     
			iface->result = -ENODEV;
			pr_debug("KW: NAK on address\n");
		} else {
			/* Handle rw "quick" mode */
			if (iface->datalen == 0) {
				do_stop(iface, 0);
			} else if (iface->read_write == I2C_SMBUS_READ) {
				iface->state = state_read;
				if (iface->datalen > 1)
					write_reg(reg_control, KW_I2C_CTL_AAK);
			} else {
				iface->state = state_write;
				write_reg(reg_data, *(iface->data++));
				iface->datalen--;
			}
		}
		write_reg(reg_isr, KW_I2C_IRQ_ADDR);
	}

	if (isr & KW_I2C_IRQ_DATA) {
		if (iface->state == state_read) {
			*(iface->data++) = read_reg(reg_data);
			write_reg(reg_isr, KW_I2C_IRQ_DATA);
			iface->datalen--;
			if (iface->datalen == 0)
				iface->state = state_stop;
			else if (iface->datalen == 1)
				write_reg(reg_control, 0);
		} else if (iface->state == state_write) {
			/* Check ack status */
			ack = read_reg(reg_status);
			if ((ack & KW_I2C_STAT_LAST_AAK) == 0) {
				pr_debug("KW: nack on data write (%x): %x\n",
				    iface->data[-1], ack);
				do_stop(iface, -EIO);
			} else if (iface->datalen) {
				write_reg(reg_data, *(iface->data++));
				iface->datalen--;
			} else {
				write_reg(reg_control, KW_I2C_CTL_STOP);
				iface->state = state_stop;
				iface->result = 0;
			}
			write_reg(reg_isr, KW_I2C_IRQ_DATA);
		} else {
			write_reg(reg_isr, KW_I2C_IRQ_DATA);
			WRONG_STATE("KW_I2C_IRQ_DATA"); 
			if (iface->state != state_stop)
				do_stop(iface, -EIO);
		}
	}

	if (isr & KW_I2C_IRQ_STOP) {
		write_reg(reg_isr, KW_I2C_IRQ_STOP);
		if (iface->state != state_stop) {
			WRONG_STATE("KW_I2C_IRQ_STOP");
			iface->result = -EIO;
		}
		iface->state = state_idle;
		write_reg(reg_ier, 0x00);
#ifndef POLLED_MODE
		complete(&iface->complete);
#endif /* POLLED_MODE */			
	}

	if (isr & KW_I2C_IRQ_START)
		write_reg(reg_isr, KW_I2C_IRQ_START);
}