⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pxa2xx_spi.c

📁 pxa3xx ssp driver for linux
💻 C
📖 第 1 页 / 共 4 页
字号:
         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->write = drv_data->tx ? chip->write : null_writer;
         drv_data->read = drv_data->rx ? chip->read : null_reader;
         drv_data->cs_change = transfer->cs_change;
 
         /* Change speed and bit per word on a per transfer */
         if (transfer->speed_hz || transfer->bits_per_word) {
 
                 /* Disable clock */
                 write_SSCR0(chip->cr0 & ~SSCR0_SSE, reg);
                 cr0 = chip->cr0;
                 bits = chip->bits_per_word;
                 speed = chip->speed_hz;
 
                 if (transfer->speed_hz)
                         speed = transfer->speed_hz;
 
                 if (transfer->bits_per_word)
                         bits = transfer->bits_per_word;
 
                 if (reg == SSP1_VIRT)
                         clk_div = SSP1_SerClkDiv(speed);
                 else if (reg == SSP2_VIRT)
                         clk_div = SSP2_SerClkDiv(speed);
                 else if (reg == SSP3_VIRT)
                         clk_div = SSP3_SerClkDiv(speed);
 
                 if (bits <= 8) {
                         drv_data->n_bytes = 1;
                         drv_data->dma_width = DCMD_WIDTH1;
                         drv_data->read = drv_data->read != null_reader ?
                                                 u8_reader : null_reader;
                         drv_data->write = drv_data->write != null_writer ?
                                                 u8_writer : null_writer;
                 } else if (bits <= 16) {
                         drv_data->n_bytes = 2;
                         drv_data->dma_width = DCMD_WIDTH2;
                         drv_data->read = drv_data->read != null_reader ?
                                                 u16_reader : null_reader;
                         drv_data->write = drv_data->write != null_writer ?
                                                 u16_writer : null_writer;
                 } else if (bits <= 32) {
                         drv_data->n_bytes = 4;
                         drv_data->dma_width = DCMD_WIDTH4;
                         drv_data->read = drv_data->read != null_reader ?
                                                 u32_reader : null_reader;
                         drv_data->write = drv_data->write != null_writer ?
                                                 u32_writer : null_writer;
                 }
 
                 cr0 = clk_div
                         | SSCR0_Motorola
                         | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
                         | SSCR0_SSE
                         | (bits > 16 ? SSCR0_EDSS : 0);
 
                 /* Start it back up */
                 write_SSCR0(cr0, reg);
         }
 
         message->state = RUNNING_STATE;
 
         /* Try to map dma buffer and do a dma transfer if successful */
         if ((drv_data->dma_mapped = map_dma_buffers(drv_data))) {
 
                 /* Ensure we have the correct interrupt handler */
                 drv_data->transfer_handler = dma_transfer;
 
                 /* Setup rx DMA Channel */
                 DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
                 DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
                 DTADR(drv_data->rx_channel) = drv_data->rx_dma;
                 if (drv_data->rx == drv_data->null_dma_buf)
                         /* No target address increment */
                         DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
                                                         | drv_data->dma_width
                                                         | chip->dma_burst_size
                                                         | drv_data->len;
                 else
                         DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
                                                         | DCMD_FLOWSRC
                                                         | drv_data->dma_width
                                                         | chip->dma_burst_size
                                                         | drv_data->len;

                 /* Setup tx DMA Channel */
                 DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
                 DSADR(drv_data->tx_channel) = drv_data->tx_dma;
                 DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
                 if (drv_data->tx == drv_data->null_dma_buf)
                         /* No source address increment */
                         DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
                                                         | drv_data->dma_width
                                                        | chip->dma_burst_size
                                                         | drv_data->len;
                 else
                         DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
                                                         | DCMD_FLOWTRG
                                                         | drv_data->dma_width
                                                         | chip->dma_burst_size
                                                         | drv_data->len;
 
                 /* Enable dma end irqs on SSP to detect end of transfer */
                 if (drv_data->ssp_type == PXA25x_SSP)
                         DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;
 
                 /* Fix me, need to handle cs polarity */
                 drv_data->cs_control(PXA2XX_CS_ASSERT);
 
                 /* Go baby, go */
                 write_SSSR(drv_data->clear_sr, reg);
                 DCSR(drv_data->rx_channel) |= DCSR_RUN;
                 DCSR(drv_data->tx_channel) |= DCSR_RUN;
                 if (drv_data->ssp_type != PXA25x_SSP)
                         write_SSTO(chip->timeout, reg);
                 write_SSCR1(chip->cr1
                                 | chip->dma_threshold
                                 | drv_data->dma_cr1,
                                 reg);
         } else {
                 /* Ensure we have the correct interrupt handler */
                 drv_data->transfer_handler = interrupt_transfer;
 
                 /* Fix me, need to handle cs polarity */
                 drv_data->cs_control(PXA2XX_CS_ASSERT);
 
                 /* Go baby, go */
                 write_SSSR(drv_data->clear_sr, reg);
                 if (drv_data->ssp_type != PXA25x_SSP)
                         write_SSTO(chip->timeout, reg);
                 write_SSCR1(chip->cr1
                                 | chip->threshold
                                 | drv_data->int_cr1,
                                 reg);
         }
 }
 
 static void pump_messages(void *data)
 {
         struct driver_data *drv_data = data;
         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);
 
         /* 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 SSP 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);
 
         drv_data->busy = 1;
         spin_unlock_irqrestore(&drv_data->lock, flags);
 }
 
 static int transfer(struct spi_device *spi, struct spi_message *msg)
 {
         struct driver_data *drv_data = spi_master_get_devdata(spi->master);
         unsigned long flags;
 
         spin_lock_irqsave(&drv_data->lock, flags);
 
         if (drv_data->run == QUEUE_STOPPED) {
                 spin_unlock_irqrestore(&drv_data->lock, flags);
                 return -ESHUTDOWN;
         }
 
         msg->actual_length = 0;
         msg->status = -EINPROGRESS;
         msg->state = START_STATE;
 
         list_add_tail(&msg->queue, &drv_data->queue);
 
         if (drv_data->run == QUEUE_RUNNING && !drv_data->busy)
                 queue_work(drv_data->workqueue, &drv_data->pump_messages);
 
         spin_unlock_irqrestore(&drv_data->lock, flags);
 
         return 0;
 }
 
 static int setup(struct spi_device *spi)
 {
         struct pxa2xx_spi_chip *chip_info = NULL;
         struct chip_data *chip;
         struct driver_data *drv_data = spi_master_get_devdata(spi->master);
         unsigned int clk_div;
 
         if (!spi->bits_per_word)
                 spi->bits_per_word = 8;
 
         if (drv_data->ssp_type != PXA25x_SSP
                         && (spi->bits_per_word < 4 || spi->bits_per_word > 32))
                 return -EINVAL;
         else if (spi->bits_per_word < 4 || spi->bits_per_word > 16)
                 return -EINVAL;
 
         /* Only alloc (or use chip_info) on first setup */
         chip = spi_get_ctldata(spi);
         if (chip == NULL) {
                 chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
                 if (!chip)
                         return -ENOMEM;
 
                 chip->cs_control = null_cs_control;
                 chip->enable_dma = 0;
                 chip->timeout = SSP_TIMEOUT(1000);
                 chip->threshold = SSCR1_RxTresh(1) | SSCR1_TxTresh(1);
                 chip->dma_burst_size = drv_data->master_info->enable_dma ?
                                         DCMD_BURST8 : 0;
 
                 chip_info = spi->controller_data;
         }
 
         /* chip_info isn't always needed */
         if (chip_info) {
                 if (chip_info->cs_control)
                         chip->cs_control = chip_info->cs_control;
 
                 chip->timeout = SSP_TIMEOUT(chip_info->timeout_microsecs);
 
                 chip->threshold = SSCR1_RxTresh(chip_info->rx_threshold)
                                         | SSCR1_TxTresh(chip_info->tx_threshold);
 
                 chip->enable_dma = chip_info->dma_burst_size != 0
                                         && drv_data->master_info->enable_dma;
                 chip->dma_threshold = 0;
 
                 if (chip->enable_dma) {
                         if (chip_info->dma_burst_size <= 8) {
                                 chip->dma_threshold = SSCR1_RxTresh(8)
                                                         | SSCR1_TxTresh(8);
                                 chip->dma_burst_size = DCMD_BURST8;
                         } else if (chip_info->dma_burst_size <= 16) {
                                 chip->dma_threshold = SSCR1_RxTresh(16)
                                                         | SSCR1_TxTresh(16);
                                 chip->dma_burst_size = DCMD_BURST16;
                         } else {
                                 chip->dma_threshold = SSCR1_RxTresh(32)
                                                         | SSCR1_TxTresh(32);
                                 chip->dma_burst_size = DCMD_BURST32;
                         }
                 }
 
 
                 if (chip_info->enable_loopback)
                         chip->cr1 = SSCR1_LBM;
         }
 
         if (drv_data->ioaddr == SSP1_VIRT)
                 clk_div = SSP1_SerClkDiv(spi->max_speed_hz);
         else if (drv_data->ioaddr == SSP2_VIRT)
                 clk_div = SSP2_SerClkDiv(spi->max_speed_hz);
         else if (drv_data->ioaddr == SSP3_VIRT)
                 clk_div = SSP3_SerClkDiv(spi->max_speed_hz);
         else
                 return -ENODEV;
         chip->speed_hz = spi->max_speed_hz;
 
         chip->cr0 = clk_div
                         | SSCR0_Motorola
                         | SSCR0_DataSize(spi->bits_per_word > 16 ?
                                 spi->bits_per_word - 16 : spi->bits_per_word)
                         | SSCR0_SSE
                         | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
         chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) << 4)
                         | (((spi->mode & SPI_CPOL) != 0) << 3);
 
         /* NOTE:  PXA25x_SSP _could_ use external clocking ... */
         if (drv_data->ssp_type != PXA25x_SSP)
                 dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
                                 spi->bits_per_word,
                                 (CLOCK_SPEED_HZ)
                                         / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
                                 spi->mode & 0x3);
         else
                 dev_dbg(&spi->dev, "%d bits/word, %d Hz, mode %d\n",
                                 spi->bits_per_word,
                                 (CLOCK_SPEED_HZ/2)
                                         / (1 + ((chip->cr0 & SSCR0_SCR) >> 8)),
                                 spi->mode & 0x3);
 
         if (spi->bits_per_word <= 8) {
                 chip->n_bytes = 1;
                 chip->dma_width = DCMD_WIDTH1;
                 chip->read = u8_reader;
                 chip->write = u8_writer;
         } else if (spi->bits_per_word <= 16) {
                 chip->n_bytes = 2;
                 chip->dma_width = DCMD_WIDTH2;
                 chip->read = u16_reader;
                 chip->write = u16_writer;
         } else if (spi->bits_per_word <= 32) {
                 chip->cr0 |= SSCR0_EDSS;
                 chip->n_bytes = 4;
                 chip->dma_width = DCMD_WIDTH4;
                 chip->read = u32_reader;
                 chip->write = u32_writer;
         } else {
                 dev_err(&spi->dev, "invalid wordsize\n");
                 kfree(chip);
                 return -ENODEV;
         }
         chip->bits_per_word = spi->bits_per_word;
 
         spi_set_ctldata(spi, chip);
 
         return 0;
 }
 
 static void cleanup(const struct spi_device *spi)
 {
         struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
 
         kfree(chip);
 }
 
 static int init_queue(struct driver_data *drv_data)
 {
         INIT_LIST_HEAD(&drv_data->queue);
         spin_lock_init(&drv_data->lock);
 
         drv_data->run = QUEUE_STOPPED;
         drv_data->busy = 0;
 
         tasklet_init(&drv_data->pump_transfers,
                         pump_transfers, (unsigned long)drv_data);
 
         INIT_WORK(&drv_data->pump_messages, pump_messages, drv_data);
         drv_data->workqueue = create_singlethread_workqueue(
                                         drv_data->master->cdev.dev->bus_id);
         if (drv_data->workqueue == NULL)
                 return -EBUSY;
 
         return 0;
 }
 
 static int start_queue(struct driver_data *drv_data)
 {
         unsigned long flags;
 
         spin_lock_irqsave(&drv_data->lock, flags);
 
         if (drv_data->run == QUEUE_RUNNING || drv_data->busy) {

⌨️ 快捷键说明

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