예제 #1
0
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);
}