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 + -
显示快捷键?