spi_imx.c

来自「linux 内核源代码」· C语言 代码 · 共 1,763 行 · 第 1/4 页

C
1,763
字号
	message = drv_data->cur_msg;	/* Handle for abort */	if (message->state == ERROR_STATE) {		message->status = -EIO;		giveback(message, drv_data);		return;	}	/* Handle end of message */	if (message->state == DONE_STATE) {		message->status = 0;		giveback(message, drv_data);		return;	}	chip = drv_data->cur_chip;	/* Delay if requested at end of transfer*/	transfer = drv_data->cur_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);	} else {		/* START_STATE */		message->state = RUNNING_STATE;		drv_data->cs_control = chip->cs_control;	}	transfer = drv_data->cur_transfer;	drv_data->tx = (void *)transfer->tx_buf;	drv_data->tx_end = drv_data->tx + transfer->len;	drv_data->rx = transfer->rx_buf;	drv_data->rx_end = drv_data->rx + transfer->len;	drv_data->rx_dma = transfer->rx_dma;	drv_data->tx_dma = transfer->tx_dma;	drv_data->len = transfer->len;	drv_data->cs_change = transfer->cs_change;	drv_data->rd_only = (drv_data->tx == NULL);	regs = drv_data->regs;	control = readl(regs + SPI_CONTROL);	/* Bits per word setup */	tmp = transfer->bits_per_word;	if (tmp == 0) {		/* Use device setup */		tmp = chip->bits_per_word;		drv_data->n_bytes = chip->n_bytes;	} else		/* Use per-transfer setup */		drv_data->n_bytes = (tmp <= 8) ? 1 : 2;	u32_EDIT(control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);	/* Speed setup (surely valid because already checked) */	tmp = transfer->speed_hz;	if (tmp == 0)		tmp = chip->max_speed_hz;	tmp = spi_data_rate(tmp);	u32_EDIT(control, SPI_CONTROL_DATARATE, tmp);	writel(control, regs + SPI_CONTROL);	/* Assert device chip-select */	drv_data->cs_control(SPI_CS_ASSERT);	/* DMA cannot read/write SPI FIFOs other than 16 bits at a time; hence	   if bits_per_word is less or equal 8 PIO transfers are performed.	   Moreover DMA is convinient for transfer length bigger than FIFOs	   byte size. */	if ((drv_data->n_bytes == 2) &&		(drv_data->len > SPI_FIFO_DEPTH*SPI_FIFO_BYTE_WIDTH) &&		(map_dma_buffers(drv_data) == 0)) {		dev_dbg(&drv_data->pdev->dev,			"pump dma transfer\n"			"    tx      = %p\n"			"    tx_dma  = %08X\n"			"    rx      = %p\n"			"    rx_dma  = %08X\n"			"    len     = %d\n",			drv_data->tx,			(unsigned int)drv_data->tx_dma,			drv_data->rx,			(unsigned int)drv_data->rx_dma,			drv_data->len);		/* Ensure we have the correct interrupt handler */		drv_data->transfer_handler = dma_transfer;		/* Trigger transfer */		writel(readl(regs + SPI_CONTROL) | SPI_CONTROL_XCH,			regs + SPI_CONTROL);		/* Setup tx DMA */		if (drv_data->tx)			/* Linear source address */			CCR(drv_data->tx_channel) =				CCR_DMOD_FIFO |				CCR_SMOD_LINEAR |				CCR_SSIZ_32 | CCR_DSIZ_16 |				CCR_REN;		else			/* Read only transfer -> fixed source address for			   dummy write to achive read */			CCR(drv_data->tx_channel) =				CCR_DMOD_FIFO |				CCR_SMOD_FIFO |				CCR_SSIZ_32 | CCR_DSIZ_16 |				CCR_REN;		imx_dma_setup_single(			drv_data->tx_channel,			drv_data->tx_dma,			drv_data->len,			drv_data->rd_data_phys + 4,			DMA_MODE_WRITE);		if (drv_data->rx) {			/* Setup rx DMA for linear destination address */			CCR(drv_data->rx_channel) =				CCR_DMOD_LINEAR |				CCR_SMOD_FIFO |				CCR_DSIZ_32 | CCR_SSIZ_16 |				CCR_REN;			imx_dma_setup_single(				drv_data->rx_channel,				drv_data->rx_dma,				drv_data->len,				drv_data->rd_data_phys,				DMA_MODE_READ);			imx_dma_enable(drv_data->rx_channel);			/* Enable SPI interrupt */			writel(SPI_INTEN_RO, regs + SPI_INT_STATUS);			/* Set SPI to request DMA service on both			   Rx and Tx half fifo watermark */			writel(SPI_DMA_RHDEN | SPI_DMA_THDEN, regs + SPI_DMA);		} else			/* Write only access -> set SPI to request DMA			   service on Tx half fifo watermark */			writel(SPI_DMA_THDEN, regs + SPI_DMA);		imx_dma_enable(drv_data->tx_channel);	} else {		dev_dbg(&drv_data->pdev->dev,			"pump pio transfer\n"			"    tx      = %p\n"			"    rx      = %p\n"			"    len     = %d\n",			drv_data->tx,			drv_data->rx,			drv_data->len);		/* Ensure we have the correct interrupt handler	*/		if (drv_data->rx)			drv_data->transfer_handler = interrupt_transfer;		else			drv_data->transfer_handler = interrupt_wronly_transfer;		/* Enable SPI interrupt */		if (drv_data->rx)			writel(SPI_INTEN_TH | SPI_INTEN_RO,				regs + SPI_INT_STATUS);		else			writel(SPI_INTEN_TH, regs + SPI_INT_STATUS);	}}static void pump_messages(struct work_struct *work){	struct driver_data *drv_data =				container_of(work, struct driver_data, work);	unsigned long flags;	/* Lock queue and check for queue work */	spin_lock_irqsave(&drv_data->lock, flags);	if (list_empty(&drv_data->queue) || drv_data->run == QUEUE_STOPPED) {		drv_data->busy = 0;		spin_unlock_irqrestore(&drv_data->lock, flags);		return;	}	/* Make sure we are not already running a message */	if (drv_data->cur_msg) {		spin_unlock_irqrestore(&drv_data->lock, flags);		return;	}	/* Extract head of queue */	drv_data->cur_msg = list_entry(drv_data->queue.next,					struct spi_message, queue);	list_del_init(&drv_data->cur_msg->queue);	drv_data->busy = 1;	spin_unlock_irqrestore(&drv_data->lock, flags);	/* Initial message state */	drv_data->cur_msg->state = START_STATE;	drv_data->cur_transfer = list_entry(drv_data->cur_msg->transfers.next,						struct spi_transfer,						transfer_list);	/* Setup the SPI using the per chip configuration */	drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi);	restore_state(drv_data);	/* Mark as busy and launch transfers */	tasklet_schedule(&drv_data->pump_transfers);}static int transfer(struct spi_device *spi, struct spi_message *msg){	struct driver_data *drv_data = spi_master_get_devdata(spi->master);	u32 min_speed_hz, max_speed_hz, tmp;	struct spi_transfer *trans;	unsigned long flags;	msg->actual_length = 0;	/* Per transfer setup check */	min_speed_hz = spi_speed_hz(SPI_CONTROL_DATARATE_MIN);	max_speed_hz = spi->max_speed_hz;	list_for_each_entry(trans, &msg->transfers, transfer_list) {		tmp = trans->bits_per_word;		if (tmp > 16) {			dev_err(&drv_data->pdev->dev,				"message rejected : "				"invalid transfer bits_per_word (%d bits)\n",				tmp);			goto msg_rejected;		}		tmp = trans->speed_hz;		if (tmp) {			if (tmp < min_speed_hz) {				dev_err(&drv_data->pdev->dev,					"message rejected : "					"device min speed (%d Hz) exceeds "					"required transfer speed (%d Hz)\n",					min_speed_hz,					tmp);				goto msg_rejected;			} else if (tmp > max_speed_hz) {				dev_err(&drv_data->pdev->dev,					"message rejected : "					"transfer speed (%d Hz) exceeds "					"device max speed (%d Hz)\n",					tmp,					max_speed_hz);				goto msg_rejected;			}		}	}	/* Message accepted */	msg->status = -EINPROGRESS;	msg->state = START_STATE;	spin_lock_irqsave(&drv_data->lock, flags);	if (drv_data->run == QUEUE_STOPPED) {		spin_unlock_irqrestore(&drv_data->lock, flags);		return -ESHUTDOWN;	}	list_add_tail(&msg->queue, &drv_data->queue);	if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)		queue_work(drv_data->workqueue, &drv_data->work);	spin_unlock_irqrestore(&drv_data->lock, flags);	return 0;msg_rejected:	/* Message rejected and not queued */	msg->status = -EINVAL;	msg->state = ERROR_STATE;	if (msg->complete)		msg->complete(msg->context);	return -EINVAL;}/* the spi->mode bits understood by this driver: */#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)/* On first setup bad values must free chip_data memory since will cause   spi_new_device to fail. Bad value setup from protocol driver are simply not   applied and notified to the calling driver. */static int setup(struct spi_device *spi){	struct spi_imx_chip *chip_info;	struct chip_data *chip;	int first_setup = 0;	u32 tmp;	int status = 0;	if (spi->mode & ~MODEBITS) {		dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",			spi->mode & ~MODEBITS);		return -EINVAL;	}	/* Get controller data */	chip_info = spi->controller_data;	/* Get controller_state */	chip = spi_get_ctldata(spi);	if (chip == NULL) {		first_setup = 1;		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);		if (!chip) {			dev_err(&spi->dev,				"setup - cannot allocate controller state\n");			return -ENOMEM;		}		chip->control = SPI_DEFAULT_CONTROL;		if (chip_info == NULL) {			/* spi_board_info.controller_data not is supplied */			chip_info = kzalloc(sizeof(struct spi_imx_chip),						GFP_KERNEL);			if (!chip_info) {				dev_err(&spi->dev,					"setup - "					"cannot allocate controller data\n");				status = -ENOMEM;				goto err_first_setup;			}			/* Set controller data default value */			chip_info->enable_loopback =						SPI_DEFAULT_ENABLE_LOOPBACK;			chip_info->enable_dma = SPI_DEFAULT_ENABLE_DMA;			chip_info->ins_ss_pulse = 1;			chip_info->bclk_wait = SPI_DEFAULT_PERIOD_WAIT;			chip_info->cs_control = null_cs_control;		}	}	/* Now set controller state based on controller data */	if (first_setup) {		/* SPI loopback */		if (chip_info->enable_loopback)			chip->test = SPI_TEST_LBC;		else			chip->test = 0;		/* SPI dma driven */		chip->enable_dma = chip_info->enable_dma;		/* SPI /SS pulse between spi burst */		if (chip_info->ins_ss_pulse)			u32_EDIT(chip->control,				SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_1);		else			u32_EDIT(chip->control,				SPI_CONTROL_SSCTL, SPI_CONTROL_SSCTL_0);		/* SPI bclk waits between each bits_per_word spi burst */		if (chip_info->bclk_wait > SPI_PERIOD_MAX_WAIT) {			dev_err(&spi->dev,				"setup - "				"bclk_wait exceeds max allowed (%d)\n",				SPI_PERIOD_MAX_WAIT);			goto err_first_setup;		}		chip->period = SPI_PERIOD_CSRC_BCLK |				(chip_info->bclk_wait & SPI_PERIOD_WAIT);	}	/* SPI mode */	tmp = spi->mode;	if (tmp & SPI_CS_HIGH) {		u32_EDIT(chip->control,				SPI_CONTROL_SSPOL, SPI_CONTROL_SSPOL_ACT_HIGH);	}	switch (tmp & SPI_MODE_3) {	case SPI_MODE_0:		tmp = 0;		break;	case SPI_MODE_1:		tmp = SPI_CONTROL_PHA_1;		break;	case SPI_MODE_2:		tmp = SPI_CONTROL_POL_ACT_LOW;		break;	default:		/* SPI_MODE_3 */		tmp = SPI_CONTROL_PHA_1 | SPI_CONTROL_POL_ACT_LOW;		break;	}	u32_EDIT(chip->control, SPI_CONTROL_POL | SPI_CONTROL_PHA, tmp);	/* SPI word width */	tmp = spi->bits_per_word;	if (tmp == 0) {		tmp = 8;		spi->bits_per_word = 8;	} else if (tmp > 16) {		status = -EINVAL;		dev_err(&spi->dev,			"setup - "			"invalid bits_per_word (%d)\n",			tmp);		if (first_setup)			goto err_first_setup;		else {			/* Undo setup using chip as backup copy */			tmp = chip->bits_per_word;			spi->bits_per_word = tmp;		}	}	chip->bits_per_word = tmp;	u32_EDIT(chip->control, SPI_CONTROL_BITCOUNT_MASK, tmp - 1);	chip->n_bytes = (tmp <= 8) ? 1 : 2;	/* SPI datarate */	tmp = spi_data_rate(spi->max_speed_hz);	if (tmp == SPI_CONTROL_DATARATE_BAD) {		status = -EINVAL;		dev_err(&spi->dev,			"setup - "			"HW min speed (%d Hz) exceeds required "			"max speed (%d Hz)\n",			spi_speed_hz(SPI_CONTROL_DATARATE_MIN),			spi->max_speed_hz);		if (first_setup)			goto err_first_setup;		else			/* Undo setup using chip as backup copy */			spi->max_speed_hz = chip->max_speed_hz;	} else {		u32_EDIT(chip->control, SPI_CONTROL_DATARATE, tmp);		/* Actual rounded max_speed_hz */		tmp = spi_speed_hz(tmp);		spi->max_speed_hz = tmp;		chip->max_speed_hz = tmp;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?