📄 pxa2xx_spi.c
字号:
msg = drv_data->cur_msg;
drv_data->cur_msg = NULL;
drv_data->cur_transfer = NULL;
drv_data->cur_chip = NULL;
queue_work(drv_data->workqueue, &drv_data->pump_messages);
spin_unlock_irqrestore(&drv_data->lock, flags);
last_transfer = list_entry(msg->transfers.prev,
struct spi_transfer,
transfer_list);
if (!last_transfer->cs_change)
drv_data->cs_control(PXA2XX_CS_DEASSERT);
msg->state = NULL;
if (msg->complete)
msg->complete(msg->context);
}
static int wait_ssp_rx_stall(void *ioaddr)
{
unsigned long limit = loops_per_jiffy << 1;
while ((read_SSSR(ioaddr) & SSSR_BSY) && limit--)
cpu_relax();
return limit;
}
static int wait_dma_channel_stop(int channel)
{
unsigned long limit = loops_per_jiffy << 1;
while (!(DCSR(channel) & DCSR_STOPSTATE) && limit--)
cpu_relax();
return limit;
}
static void dma_handler(int channel, void *data, struct pt_regs *regs)
{
struct driver_data *drv_data = data;
struct spi_message *msg = drv_data->cur_msg;
void *reg = drv_data->ioaddr;
u32 irq_status = DCSR(channel) & DMA_INT_MASK;
u32 trailing_sssr = 0;
if (irq_status & DCSR_BUSERR) {
/* Disable interrupts, clear status and reset DMA */
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(0, reg);
write_SSSR(drv_data->clear_sr, reg);
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
if (flush(drv_data) == 0)
dev_err(&drv_data->pdev->dev,
"dma_handler: flush fail\n");
unmap_dma_buffers(drv_data);
if (channel == drv_data->tx_channel)
dev_err(&drv_data->pdev->dev,
"dma_handler: bad bus address on "
"tx channel %d, source %x target = %x\n",
channel, DSADR(channel), DTADR(channel));
else
dev_err(&drv_data->pdev->dev,
"dma_handler: bad bus address on "
"rx channel %d, source %x target = %x\n",
channel, DSADR(channel), DTADR(channel));
msg->state = ERROR_STATE;
tasklet_schedule(&drv_data->pump_transfers);
}
/* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
if ((drv_data->ssp_type == PXA25x_SSP)
&& (channel == drv_data->tx_channel)
&& (irq_status & DCSR_ENDINTR)) {
/* 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");
/* Clear and disable interrupts on SSP and DMA channels*/
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
write_SSSR(drv_data->clear_sr, reg);
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");
unmap_dma_buffers(drv_data);
/* Read trailing bytes */
/* Calculate number of trailing bytes, read them */
trailing_sssr = read_SSSR(reg);
if ((trailing_sssr & 0xf008) != 0xf000) {
drv_data->rx = drv_data->rx_end -
(((trailing_sssr >> 12) & 0x0f) + 1);
drv_data->read(drv_data);
}
msg->actual_length += drv_data->len;
/* Release chip select if requested, transfer delays are
* handled in pump_transfers */
if (drv_data->cs_change)
drv_data->cs_control(PXA2XX_CS_DEASSERT);
/* Move to next transfer */
msg->state = next_transfer(drv_data);
/* Schedule transfer tasklet */
tasklet_schedule(&drv_data->pump_transfers);
}
}
static irqreturn_t dma_transfer(struct driver_data *drv_data)
{
u32 irq_status;
u32 trailing_sssr = 0;
struct spi_message *msg = drv_data->cur_msg;
void *reg = drv_data->ioaddr;
irq_status = read_SSSR(reg) & drv_data->mask_sr;
if (irq_status & SSSR_ROR) {
/* Clear and disable interrupts on SSP and DMA channels*/
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(0, reg);
write_SSSR(drv_data->clear_sr, reg);
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
unmap_dma_buffers(drv_data);
if (flush(drv_data) == 0)
dev_err(&drv_data->pdev->dev,
"dma_transfer: flush fail\n");
dev_warn(&drv_data->pdev->dev, "dma_transfer: fifo overun\n");
drv_data->cur_msg->state = ERROR_STATE;
tasklet_schedule(&drv_data->pump_transfers);
return IRQ_HANDLED;
}
/* Check for false positive timeout */
if ((irq_status & SSSR_TINT) && DCSR(drv_data->tx_channel) & DCSR_RUN) {
write_SSSR(SSSR_TINT, reg);
return IRQ_HANDLED;
}
if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {
/* Clear and disable interrupts on SSP and DMA channels*/
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(0, reg);
write_SSSR(drv_data->clear_sr, reg);
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_transfer: 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");
unmap_dma_buffers(drv_data);
/* Calculate number of trailing bytes, read them */
trailing_sssr = read_SSSR(reg);
if ((trailing_sssr & 0xf008) != 0xf000) {
drv_data->rx = drv_data->rx_end -
(((trailing_sssr >> 12) & 0x0f) + 1);
drv_data->read(drv_data);
}
msg->actual_length += drv_data->len;
/* Release chip select if requested, transfer delays are
* handled in pump_transfers */
if (drv_data->cs_change)
drv_data->cs_control(PXA2XX_CS_DEASSERT);
/* Move to next transfer */
msg->state = next_transfer(drv_data);
/* Schedule transfer tasklet */
tasklet_schedule(&drv_data->pump_transfers);
return IRQ_HANDLED;
}
/* Opps problem detected */
return IRQ_NONE;
}
static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
{
struct spi_message *msg = drv_data->cur_msg;
void *reg = drv_data->ioaddr;
unsigned long limit = loops_per_jiffy << 1;
u32 irq_status;
u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
while ((irq_status = read_SSSR(reg) & irq_mask)) {
if (irq_status & SSSR_ROR) {
/* Clear and disable interrupts */
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(0, reg);
write_SSSR(drv_data->clear_sr, reg);
if (flush(drv_data) == 0)
dev_err(&drv_data->pdev->dev,
"interrupt_transfer: flush fail\n");
/* Stop the SSP */
dev_warn(&drv_data->pdev->dev,
"interrupt_transfer: fifo overun\n");
msg->state = ERROR_STATE;
tasklet_schedule(&drv_data->pump_transfers);
return IRQ_HANDLED;
}
/* Look for false positive timeout */
if ((irq_status & SSSR_TINT)
&& (drv_data->rx < drv_data->rx_end))
write_SSSR(SSSR_TINT, reg);
/* Pump data */
drv_data->read(drv_data);
drv_data->write(drv_data);
if (drv_data->tx == drv_data->tx_end) {
/* Disable tx interrupt */
write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg);
irq_mask = drv_data->mask_sr & ~SSSR_TFS;
/* PXA25x_SSP has no timeout, read trailing bytes */
if (drv_data->ssp_type == PXA25x_SSP) {
while ((read_SSSR(reg) & SSSR_BSY) && limit--)
drv_data->read(drv_data);
if (limit == 0)
dev_err(&drv_data->pdev->dev,
"interrupt_transfer: "
"trailing byte read failed\n");
}
}
if ((irq_status & SSSR_TINT)
|| (drv_data->rx == drv_data->rx_end)) {
/* Clear timeout */
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(0, reg);
write_SSSR(drv_data->clear_sr, reg);
/* Update total byte transfered */
msg->actual_length += drv_data->len;
/* Release chip select if requested, transfer delays are
* handled in pump_transfers */
if (drv_data->cs_change)
drv_data->cs_control(PXA2XX_CS_DEASSERT);
/* Move to next transfer */
msg->state = next_transfer(drv_data);
/* Schedule transfer tasklet */
tasklet_schedule(&drv_data->pump_transfers);
}
}
/* We did something */
return IRQ_HANDLED;
}
static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs)
{
struct driver_data *drv_data = (struct driver_data *)dev_id;
void *reg = drv_data->ioaddr;
if (!drv_data->cur_msg) {
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP)
write_SSTO(0, reg);
write_SSSR(drv_data->clear_sr, reg);
dev_err(&drv_data->pdev->dev, "bad message state "
"in interrupt handler");
/* Never fail */
return IRQ_HANDLED;
}
return drv_data->transfer_handler(drv_data);
}
static void pump_transfers(unsigned long data)
{
struct driver_data *drv_data = (struct driver_data *)data;
struct spi_message *message = NULL;
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
struct chip_data *chip = NULL;
void *reg = drv_data->ioaddr;
u32 clk_div = 0;
u8 bits = 0;
u32 speed = 0;
u32 cr0;
/* Get current state information */
message = drv_data->cur_msg;
transfer = drv_data->cur_transfer;
chip = drv_data->cur_chip;
/* Handle for abort */
if (message->state == ERROR_STATE) {
message->status = -EIO;
giveback(drv_data);
return;
}
/* Handle end of message */
if (message->state == DONE_STATE) {
message->status = 0;
giveback(drv_data);
return;
}
/* Delay if requested at end of transfer*/
if (message->state == RUNNING_STATE) {
previous = list_entry(transfer->transfer_list.prev,
struct spi_transfer,
transfer_list);
if (previous->delay_usecs)
udelay(previous->delay_usecs);
}
/* Setup the transfer state based on the type of transfer */
if (flush(drv_data) == 0) {
dev_err(&drv_data->pdev->dev, "pump_transfers: flush failed\n");
message->status = -EIO;
giveback(drv_data);
return;
}
drv_data->n_bytes = chip->n_bytes;
drv_data->dma_width = chip->dma_width;
drv_data->cs_control = chip->cs_control;
drv_data->tx = (void *)transfer->tx_buf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -