/* * Interrupt service routine. This gets called whenever an I2C interrupt * occurs. */ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) { struct dw_i2c_dev *dev = dev_id; u32 stat, enabled; enabled = dw_readl(dev, DW_IC_ENABLE); stat = dw_readl(dev, DW_IC_RAW_INTR_STAT); dev_dbg(dev->dev, "%s: %s enabled= 0x%x stat=0x%x\n", __func__, dev->adapter.name, enabled, stat); if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) return IRQ_NONE; stat = i2c_dw_read_clear_intrbits(dev); if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; dev->status = STATUS_IDLE; /* * Anytime TX_ABRT is set, the contents of the tx/rx * buffers are flushed. Make sure to skip them. */ dw_writel(dev, 0, DW_IC_INTR_MASK); goto tx_aborted; } if (stat & DW_IC_INTR_RX_OVER) { dev_err(dev->dev, "i2c fifo overflow rx tl=%d,rxflr=%d,msg len=%d,txflr=%d\n", readl(dev->base + DW_IC_RX_TL),readl(dev->base+DW_IC_RXFLR),dev->msgs[dev->msg_write_idx].len, readl(dev->base + DW_IC_TXFLR)); dev->msg_err = -EINVAL; goto tx_aborted; } if (stat & DW_IC_INTR_RX_FULL) i2c_dw_read(dev); if (stat & DW_IC_INTR_TX_EMPTY) i2c_dw_xfer_msg(dev); if (stat & DW_IC_INTR_STOP_DET) { if (dev->status & STATUS_READ_IN_PROGRESS) i2c_dw_read(dev); if (dev->status !=0) { dev_err(dev->dev, "i2c transfer was stopped unexpected\n"); dev->msg_err = -EINVAL; } } /* * No need to modify or disable the interrupt mask here. * i2c_dw_xfer_msg() will take care of it according to * the current transmit status. */ tx_aborted: if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) complete(&dev->cmd_complete); return IRQ_HANDLED; }
/* * Interrupt service routine. This gets called whenever an I2C interrupt * occurs. */ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) { struct dw_i2c_dev *dev = dev_id; u32 stat, enabled; enabled = dw_readl(dev, DW_IC_ENABLE); stat = dw_readl(dev, DW_IC_RAW_INTR_STAT); dev_dbg(dev->dev, "%s: %s enabled= 0x%x stat=0x%x\n", __func__, dev->adapter.name, enabled, stat); if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) return IRQ_NONE; stat = i2c_dw_read_clear_intrbits(dev); if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; dev->status = STATUS_IDLE; /* * Anytime TX_ABRT is set, the contents of the tx/rx * buffers are flushed. Make sure to skip them. */ dw_writel(dev, 0, DW_IC_INTR_MASK); goto tx_aborted; } if (stat & DW_IC_INTR_RX_FULL) i2c_dw_read(dev); if (stat & DW_IC_INTR_TX_EMPTY) i2c_dw_xfer_msg(dev); /* * No need to modify or disable the interrupt mask here. * i2c_dw_xfer_msg() will take care of it according to * the current transmit status. */ tx_aborted: if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) complete(&dev->cmd_complete); return IRQ_HANDLED; }
/* * Interrupt service routine. This gets called whenever an I2C master interrupt * occurs. */ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev) { u32 stat; stat = i2c_dw_read_clear_intrbits(dev); if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; dev->status = STATUS_IDLE; /* * Anytime TX_ABRT is set, the contents of the tx/rx * buffers are flushed. Make sure to skip them. */ dw_writel(dev, 0, DW_IC_INTR_MASK); goto tx_aborted; } if (stat & DW_IC_INTR_RX_FULL) i2c_dw_read(dev); if (stat & DW_IC_INTR_TX_EMPTY) i2c_dw_xfer_msg(dev); /* * No need to modify or disable the interrupt mask here. * i2c_dw_xfer_msg() will take care of it according to * the current transmit status. */ tx_aborted: if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) complete(&dev->cmd_complete); else if (unlikely(dev->flags & ACCESS_INTR_MASK)) { /* Workaround to trigger pending interrupt */ stat = dw_readl(dev, DW_IC_INTR_MASK); i2c_dw_disable_int(dev); dw_writel(dev, stat, DW_IC_INTR_MASK); } return 0; }