static irqreturn_t nuc970_spi0_irq(int irq, void *dev) { struct nuc970_spi *hw = dev; unsigned int status, i, offset; unsigned int count = hw->count; hw->count += hw->pdata->txnum+1; if (hw->rx) { for(i=0, offset=0; i<hw->pdata->txnum+1 ;i++,offset+=4) hw_rx(hw, __raw_readl(hw->regs + REG_RX0 + offset), count++); } count = hw->count; if (count < hw->len) { for(i=0, offset=0; i<hw->pdata->txnum+1 ;i++,offset+=4) { __raw_writel(hw_tx(hw, count++), hw->regs + REG_TX0 + offset); } nuc970_spi0_gobusy(hw); } else { complete(&hw->done); } status = __raw_readl(hw->regs + REG_CNTRL); __raw_writel(status, hw->regs + REG_CNTRL); return IRQ_HANDLED; }
static int nuc970_spi0_txrx(struct spi_device *spi, struct spi_transfer *t) { struct nuc970_spi *hw = (struct nuc970_spi *)to_hw(spi); int i, offset; hw->tx = t->tx_buf; hw->rx = t->rx_buf; hw->len = t->len; hw->count = 0; if(t->tx_nbits & SPI_NBITS_DUAL) { __raw_writel(__raw_readl(hw->regs + REG_CNTRL) | (0x5 << 20), hw->regs + REG_CNTRL); } else if(t->tx_nbits & SPI_NBITS_QUAD) { __raw_writel(__raw_readl(hw->regs + REG_CNTRL) | (0x3 << 20), hw->regs + REG_CNTRL); } if(t->rx_nbits & SPI_NBITS_DUAL) { __raw_writel(__raw_readl(hw->regs + REG_CNTRL) | (0x4 << 20), hw->regs + REG_CNTRL); } else if(t->rx_nbits & SPI_NBITS_QUAD) { __raw_writel(__raw_readl(hw->regs + REG_CNTRL) | (0x2 << 20), hw->regs + REG_CNTRL); } for(i=0, offset=0; i<hw->pdata->txnum+1 ;i++,offset+=4) __raw_writel(hw_tx(hw, i), hw->regs + REG_TX0 + offset); nuc970_spi0_gobusy(hw); wait_for_completion(&hw->done); if(spi->mode & (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) __raw_writel(__raw_readl(hw->regs + REG_CNTRL) & ~(0x7 << 20), hw->regs + REG_CNTRL); return hw->count; }
/* * s3c6410_spi_interrupt - spi fifo interrupt handler * @irq : interrupt number * @dev : device instance * * spi fifo interrupt handler */ static irqreturn_t s3c6410_spi_irq(int irq, void *dev) { struct s3c6410_spi *hw = dev; unsigned int pend = readl(hw->regs + S3C_SPI_STATUS); unsigned int w_tmp; unsigned int r_tmp; int err = 0; spin_lock(&hw->lock); if(pend & SPI_STUS_RX_OVERRUN_ERR) { printk("spi%d: RX FIFO overrun error\n", hw->id); writel(SPI_PND_RX_OVERRUN_CLR, hw->regs + S3C_PENDING_CLR); err = 1; } if(pend & SPI_STUS_RX_UNDERRUN_ERR) { printk("spi%d: RX FIFO underrun error\n", hw->id); writel(SPI_PND_RX_UNDERRUN_CLR, hw->regs + S3C_PENDING_CLR); err = 1; } if(pend & SPI_STUS_TX_OVERRUN_ERR) { printk("spi%d: TX FIFO overrun error\n", hw->id); writel(SPI_PND_TX_OVERRUN_CLR, hw->regs + S3C_PENDING_CLR); err = 1; } if(pend & SPI_STUS_TX_UNDERRUN_ERR) { printk("spi%d: TX FIFO underrun error\n", hw->id); writel(SPI_PND_TX_UNDERRUN_CLR, hw->regs + S3C_PENDING_CLR); err = 1; } if(err) { complete(&hw->done); return IRQ_HANDLED; } if((pend & SPI_STUS_TX_FIFORDY) && (hw->tx_done < hw->len)) { w_tmp = hw_tx(hw); writel(w_tmp, hw->regs + S3C_SPI_TX_DATA); udelay(30); hw->flag = 1; hw->tx_done++; } if(pend & (SPI_STUS_RX_FIFOLVL)) { r_tmp = readl(hw->regs + S3C_SPI_RX_DATA); hw_rx(hw, r_tmp); hw->flag = 0; hw->rx_done++; } if(hw->rx_done == hw->len && hw->tx_done == hw->len) { writel(SPI_INT_ALL_DISABLE, hw->regs + S3C_SPI_INT_EN); udelay(30); complete(&hw->done); } spin_unlock(&hw->lock); return IRQ_HANDLED; }