static void dw_writer(struct dw_spi *dws) { u32 max = tx_max(dws); u16 txw = 0; DBG_SPI("%dbyte tx:",dws->n_bytes); while (max--) { /* Set the tx word if the transfer's original "tx" is not null */ if (dws->tx_end - dws->len) { if (dws->n_bytes == 1) { txw = *(u8 *)(dws->tx); DBG_SPI("0x%02x,", *(u8 *)(dws->tx)); } else { txw = *(u16 *)(dws->tx); DBG_SPI("0x%02x,", *(u16 *)(dws->tx)); } } dw_writew(dws, SPIM_TXDR, txw); dws->tx += dws->n_bytes; } //it is neccessary wait_till_not_busy(dws); DBG_SPI("\n"); }
static ssize_t spi_write_proc_data(struct file *file, const char __user *buffer, size_t count, loff_t *data) { struct dw_spi *dws; char *buf; ssize_t ret; int reg = 0,value = 0; dws = file->private_data; buf = kzalloc(32, GFP_KERNEL); if (!buf) return 0; ret = copy_from_user(buf, buffer, count); if (ret) { return ret; } if((strstr(buf, "debug") != NULL) || (strstr(buf, "DEBUG") != NULL)) { atomic_set(&dws->debug_flag, 1); kfree(buf); printk("%s:open debug\n",__func__); return count; } else if((strstr(buf, "stop") != NULL) || (strstr(buf, "STOP") != NULL)) { atomic_set(&dws->debug_flag, 0); printk("%s:close debug\n",__func__); } else if((strstr(buf, "=") != NULL)) { printk("%s:invalid command\n",__func__); return count; } sscanf(buf, "0x%x=0x%x", ®, &value); if((reg >= SPIM_CTRLR0) && (reg <= SPIM_DMARDLR)) { dw_writew(dws, reg, value); printk("%s:write data[0x%x] to reg[0x%x] succesfully\n",__func__, value, reg); } else { printk("%s:data[0x%x] or reg[0x%x] is out of range\n",__func__, value, reg); } kfree(buf); return count; }
static int u16_writer(struct dw_spi *dws) { if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL) || (dws->tx == dws->tx_end)) return 0; dw_writew(dws, dr, *(u16 *)(dws->tx)); dws->tx += 2; wait_till_not_busy(dws); return 1; }
static int null_writer(struct dw_spi *dws) { u8 n_bytes = dws->n_bytes; if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL) || (dws->tx == dws->tx_end)) return 0; dw_writew(dws, dr, 0); dws->tx += n_bytes; wait_till_not_busy(dws); return 1; }
static void dw_writer(struct dw_spi *dws) { u32 max = tx_max(dws); u16 txw = 0; while (max--) { /* Set the tx word if the transfer's original "tx" is not null */ if (dws->tx_end - dws->len) { if (dws->n_bytes == 1) txw = *(u8 *)(dws->tx); else txw = *(u16 *)(dws->tx); } dw_writew(dws, DW_SPI_DR, txw); dws->tx += dws->n_bytes; } }
static int spi_pl330_dma_transfer(struct dw_spi *dws, int cs_change) { struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL; struct dma_chan *txchan, *rxchan; struct dma_slave_config txconf, rxconf; u16 dma_ctrl = 0; /* 1. setup DMA related registers */ if (cs_change) { spi_enable_chip(dws, 0); /* Setup peripheral's burst watermark for TX and RX FIFO */ dw_writew(dws, DW_SPI_DMARDLR, SSI_DMA_MAXBURST - 1); dw_writew(dws, DW_SPI_DMATDLR, SSI_FIFO_DEPTH - SSI_DMA_MAXBURST); if (dws->tx_dma) dma_ctrl |= 0x2; if (dws->rx_dma) dma_ctrl |= 0x1; dw_writew(dws, DW_SPI_DMACR, dma_ctrl); spi_enable_chip(dws, 1); } dws->dma_chan_done = 0; txchan = dws->txchan; rxchan = dws->rxchan; /* 2. Prepare the TX dma transfer */ txconf.direction = DMA_MEM_TO_DEV; txconf.dst_addr = dws->dma_addr; /* Note: By default the burst_len (dst_maxburst) for DMA_MEM_TO_DEV is set to 1 and the burst_size (src_addr_width) for memory is set to peripheral's configuration in PL330 driver (driver/dma/pl330.c). Therefore the config listed below can be skipped i. txconf.dst_maxburst ii. txconf.src_addr_width Max DMA width is 16-bit */ if (dws->dma_width == 1) txconf.dst_addr_width = PL330_DMA_BRSTSZ_1B; else txconf.dst_addr_width = PL330_DMA_BRSTSZ_2B; txchan->device->device_control(txchan, DMA_SLAVE_CONFIG, (unsigned long) &txconf); memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl)); dws->tx_sgl.dma_address = dws->tx_dma; dws->tx_sgl.length = dws->len; txdesc = txchan->device->device_prep_slave_sg(txchan, &dws->tx_sgl, 1, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT, NULL); txdesc->callback = spi_pl330_dma_done; txdesc->callback_param = dws; /* 3. Prepare the RX dma transfer */ rxconf.direction = DMA_DEV_TO_MEM; rxconf.src_addr = dws->dma_addr; /* Note: By default the burst_len (src_maxburst) for DMA_DEV_TO_MEM is set to 1 and the burst_size (dst_addr_width) for memory is set to peripheral's configuration in PL330 driver (driver/dma/pl330.c). Therefore the config listed below can be skipped txconf.src_maxburst txconf.dst_addr_width */ if (dws->dma_width == 1) rxconf.src_addr_width = PL330_DMA_BRSTSZ_1B; else rxconf.src_addr_width = PL330_DMA_BRSTSZ_2B; rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG, (unsigned long) &rxconf); memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl)); dws->rx_sgl.dma_address = dws->rx_dma; dws->rx_sgl.length = dws->len; rxdesc = rxchan->device->device_prep_slave_sg(rxchan, &dws->rx_sgl, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT, NULL); rxdesc->callback = spi_pl330_dma_done; rxdesc->callback_param = dws; /* rx must be started before tx due to spi instinct */ rxdesc->tx_submit(rxdesc); dma_async_issue_pending(rxchan); txdesc->tx_submit(txdesc); dma_async_issue_pending(txchan); return 0; }