static void giveback(struct pl022 *pl022) { struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; void (*curr_cs_control) (u32 command); curr_cs_control = pl022->cur_chip->cs_control; spin_lock_irqsave(&pl022->queue_lock, flags); msg = pl022->cur_msg; pl022->cur_msg = NULL; pl022->cur_transfer = NULL; pl022->cur_chip = NULL; queue_work(pl022->workqueue, &pl022->pump_messages); spin_unlock_irqrestore(&pl022->queue_lock, flags); last_transfer = list_entry(msg->transfers.prev, struct spi_transfer, transfer_list); if (last_transfer->delay_usecs) udelay(last_transfer->delay_usecs); if (!last_transfer->cs_change) curr_cs_control(SSP_CHIP_DESELECT); else { struct spi_message *next_msg; spin_lock_irqsave(&pl022->queue_lock, flags); if (list_empty(&pl022->queue)) next_msg = NULL; else next_msg = list_entry(pl022->queue.next, struct spi_message, queue); spin_unlock_irqrestore(&pl022->queue_lock, flags); if (next_msg && next_msg->spi != msg->spi) next_msg = NULL; if (!next_msg || msg->state == STATE_ERROR) curr_cs_control(SSP_CHIP_DESELECT); } msg->state = NULL; if (msg->complete) msg->complete(msg->context); clk_disable(pl022->clk); }
static void giveback(struct pl022 *pl022) { struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; void (*curr_cs_control) (u32 command); /* * This local reference to the chip select function * is needed because we set curr_chip to NULL * as a step toward termininating the message. */ curr_cs_control = pl022->cur_chip->cs_control; spin_lock_irqsave(&pl022->queue_lock, flags); msg = pl022->cur_msg; pl022->cur_msg = NULL; pl022->cur_transfer = NULL; pl022->cur_chip = NULL; queue_work(pl022->workqueue, &pl022->pump_messages); spin_unlock_irqrestore(&pl022->queue_lock, flags); last_transfer = list_entry(msg->transfers.prev, struct spi_transfer, transfer_list); /* Delay if requested before any change in chip select */ if (last_transfer->delay_usecs) /* * FIXME: This runs in interrupt context. * Is this really smart? */ udelay(last_transfer->delay_usecs); /* * Drop chip select UNLESS cs_change is true or we are returning * a message with an error, or next message is for another chip */ if (!last_transfer->cs_change) curr_cs_control(SSP_CHIP_DESELECT); else { struct spi_message *next_msg; /* Holding of cs was hinted, but we need to make sure * the next message is for the same chip. Don't waste * time with the following tests unless this was hinted. * * We cannot postpone this until pump_messages, because * after calling msg->complete (below) the driver that * sent the current message could be unloaded, which * could invalidate the cs_control() callback... */ /* get a pointer to the next message, if any */ spin_lock_irqsave(&pl022->queue_lock, flags); if (list_empty(&pl022->queue)) next_msg = NULL; else next_msg = list_entry(pl022->queue.next, struct spi_message, queue); spin_unlock_irqrestore(&pl022->queue_lock, flags); /* see if the next and current messages point * to the same chip */ if (next_msg && next_msg->spi != msg->spi) next_msg = NULL; if (!next_msg || msg->state == STATE_ERROR) curr_cs_control(SSP_CHIP_DESELECT); } msg->state = NULL; if (msg->complete) msg->complete(msg->context); /* This message is completed, so let's turn off the clock! */ clk_disable(pl022->clk); }