void pxa2xx_spi_dma_handler(int channel, void *data) { struct driver_data *drv_data = data; u32 irq_status = DCSR(channel) & DMA_INT_MASK; if (irq_status & DCSR_BUSERR) { if (channel == drv_data->tx_channel) pxa2xx_spi_dma_error_stop(drv_data, "dma_handler: bad bus address on tx channel"); else pxa2xx_spi_dma_error_stop(drv_data, "dma_handler: bad bus address on rx channel"); return; } /* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */ if ((channel == drv_data->tx_channel) && (irq_status & DCSR_ENDINTR) && (drv_data->ssp_type == PXA25x_SSP)) { /* Wait for rx to stall */ if (wait_ssp_rx_stall(drv_data->ioaddr) == 0) dev_err(&drv_data->pdev->dev, "dma_handler: ssp rx stall failed\n"); /* finish this transfer, start the next */ pxa2xx_spi_dma_transfer_complete(drv_data); } }
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data) { struct spi_message *msg = drv_data->cur_msg; /* Clear and disable interrupts on SSP and DMA channels*/ pxa2xx_spi_write(drv_data, SSCR1, pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->dma_cr1); write_SSSR_CS(drv_data, drv_data->clear_sr); DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; if (wait_dma_channel_stop(drv_data->rx_channel) == 0) dev_err(&drv_data->pdev->dev, "dma_handler: dma rx channel stop failed\n"); if (wait_ssp_rx_stall(drv_data->ioaddr) == 0) dev_err(&drv_data->pdev->dev, "dma_transfer: ssp rx stall failed\n"); pxa2xx_spi_unmap_dma_buffers(drv_data); /* update the buffer pointer for the amount completed in dma */ drv_data->rx += drv_data->len - (DCMD(drv_data->rx_channel) & DCMD_LENGTH); /* read trailing data from fifo, it does not matter how many * bytes are in the fifo just read until buffer is full * or fifo is empty, which ever occurs first */ drv_data->read(drv_data); /* return count of what was actually read */ msg->actual_length += drv_data->len - (drv_data->rx_end - drv_data->rx); /* Transfer delays and chip select release are * handled in pump_transfers or giveback */ /* Move to next transfer */ msg->state = pxa2xx_spi_next_transfer(drv_data); /* Schedule transfer tasklet */ tasklet_schedule(&drv_data->pump_transfers); }