static int rockchip_spi_pio_transfer(struct rockchip_spi *rs) { int remain = 0; do { if (rs->tx) { remain = rs->tx_end - rs->tx; rockchip_spi_pio_writer(rs); } if (rs->rx) { remain = rs->rx_end - rs->rx; rockchip_spi_pio_reader(rs); } cpu_relax(); } while (remain); /* If tx, wait until the FIFO data completely. */ if (rs->tx) wait_for_idle(rs); spi_enable_chip(rs, 0); return 0; }
static int rockchip_spi_unprepare_message(struct spi_master *master, struct spi_message *msg) { unsigned long flags; struct rockchip_spi *rs = spi_master_get_devdata(master); spin_lock_irqsave(&rs->lock, flags); /* * For DMA mode, we need terminate DMA channel and flush * fifo for the next transfer if DMA thansfer timeout. * unprepare_message() was called by core if transfer complete * or timeout. Maybe it is reasonable for error handling here. */ if (rs->use_dma) { if (rs->state & RXBUSY) { dmaengine_terminate_all(rs->dma_rx.ch); flush_fifo(rs); } if (rs->state & TXBUSY) dmaengine_terminate_all(rs->dma_tx.ch); } spin_unlock_irqrestore(&rs->lock, flags); spi_enable_chip(rs, 0); return 0; }
static int rockchip_spi_unprepare_message(struct spi_master *master, struct spi_message *msg) { struct rockchip_spi *rs = spi_master_get_devdata(master); spi_enable_chip(rs, 0); return 0; }
static void rockchip_spi_config(struct rockchip_spi *rs) { u32 div = 0; u32 dmacr = 0; u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET) | (CR0_SSD_ONE << CR0_SSD_OFFSET); cr0 |= (rs->n_bytes << CR0_DFS_OFFSET); cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET); cr0 |= (rs->tmode << CR0_XFM_OFFSET); cr0 |= (rs->type << CR0_FRF_OFFSET); if (rs->use_dma) { if (rs->tx) dmacr |= TF_DMA_EN; if (rs->rx) dmacr |= RF_DMA_EN; } /* div doesn't support odd number */ div = rs->max_freq / rs->speed; div = (div + 1) & 0xfffe; spi_enable_chip(rs, 0); writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0); writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_TXFTLR); writel_relaxed(rs->fifo_len / 2 - 1, rs->regs + ROCKCHIP_SPI_RXFTLR); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMATDLR); writel_relaxed(0, rs->regs + ROCKCHIP_SPI_DMARDLR); writel_relaxed(dmacr, rs->regs + ROCKCHIP_SPI_DMACR); spi_set_clk(rs, div); dev_dbg(rs->dev, "cr0 0x%x, div %d\n", cr0, div); spi_enable_chip(rs, 1); }
static void rockchip_spi_dma_rxcb(void *data) { unsigned long flags; struct rockchip_spi *rs = data; spin_lock_irqsave(&rs->lock, flags); rs->state &= ~RXBUSY; if (!(rs->state & TXBUSY)) { spi_enable_chip(rs, 0); spi_finalize_current_transfer(rs->master); } spin_unlock_irqrestore(&rs->lock, flags); }
static void rockchip_spi_dma_txcb(void *data) { unsigned long flags; struct rockchip_spi *rs = data; /* Wait until the FIFO data completely. */ wait_for_idle(rs); spin_lock_irqsave(&rs->lock, flags); rs->state &= ~TXBUSY; if (!(rs->state & RXBUSY)) { spi_enable_chip(rs, 0); spi_finalize_current_transfer(rs->master); } spin_unlock_irqrestore(&rs->lock, flags); }
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; }
static int rockchip_spi_probe(struct platform_device *pdev) { int ret = 0; struct rockchip_spi *rs; struct spi_master *master; struct resource *mem; master = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi)); if (!master) return -ENOMEM; platform_set_drvdata(pdev, master); rs = spi_master_get_devdata(master); memset(rs, 0, sizeof(struct rockchip_spi)); /* Get basic io resource and map it */ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); rs->regs = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(rs->regs)) { ret = PTR_ERR(rs->regs); goto err_ioremap_resource; } rs->apb_pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(rs->apb_pclk)) { dev_err(&pdev->dev, "Failed to get apb_pclk\n"); ret = PTR_ERR(rs->apb_pclk); goto err_ioremap_resource; } rs->spiclk = devm_clk_get(&pdev->dev, "spiclk"); if (IS_ERR(rs->spiclk)) { dev_err(&pdev->dev, "Failed to get spi_pclk\n"); ret = PTR_ERR(rs->spiclk); goto err_ioremap_resource; } ret = clk_prepare_enable(rs->apb_pclk); if (ret) { dev_err(&pdev->dev, "Failed to enable apb_pclk\n"); goto err_ioremap_resource; } ret = clk_prepare_enable(rs->spiclk); if (ret) { dev_err(&pdev->dev, "Failed to enable spi_clk\n"); goto err_spiclk_enable; } spi_enable_chip(rs, 0); rs->type = SSI_MOTO_SPI; rs->master = master; rs->dev = &pdev->dev; rs->max_freq = clk_get_rate(rs->spiclk); rs->fifo_len = get_fifo_len(rs); if (!rs->fifo_len) { dev_err(&pdev->dev, "Failed to get fifo length\n"); ret = -EINVAL; goto err_get_fifo_len; } spin_lock_init(&rs->lock); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); master->auto_runtime_pm = true; master->bus_num = pdev->id; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; master->num_chipselect = 2; master->dev.of_node = pdev->dev.of_node; master->bits_per_word_mask = SPI_BPW_MASK(16) | SPI_BPW_MASK(8); master->set_cs = rockchip_spi_set_cs; master->prepare_message = rockchip_spi_prepare_message; master->unprepare_message = rockchip_spi_unprepare_message; master->transfer_one = rockchip_spi_transfer_one; rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx"); if (!rs->dma_tx.ch) dev_warn(rs->dev, "Failed to request TX DMA channel\n"); rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx"); if (!rs->dma_rx.ch) { if (rs->dma_tx.ch) { dma_release_channel(rs->dma_tx.ch); rs->dma_tx.ch = NULL; } dev_warn(rs->dev, "Failed to request RX DMA channel\n"); } if (rs->dma_tx.ch && rs->dma_rx.ch) { rs->dma_tx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_TXDR); rs->dma_rx.addr = (dma_addr_t)(mem->start + ROCKCHIP_SPI_RXDR); rs->dma_tx.direction = DMA_MEM_TO_DEV; rs->dma_rx.direction = DMA_DEV_TO_MEM; master->can_dma = rockchip_spi_can_dma; master->dma_tx = rs->dma_tx.ch; master->dma_rx = rs->dma_rx.ch; } ret = devm_spi_register_master(&pdev->dev, master); if (ret) { dev_err(&pdev->dev, "Failed to register master\n"); goto err_register_master; } return 0; err_register_master: if (rs->dma_tx.ch) dma_release_channel(rs->dma_tx.ch); if (rs->dma_rx.ch) dma_release_channel(rs->dma_rx.ch); err_get_fifo_len: clk_disable_unprepare(rs->spiclk); err_spiclk_enable: clk_disable_unprepare(rs->apb_pclk); err_ioremap_resource: spi_master_put(master); return ret; }
static int rockchip_spi_transfer_one( struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { int ret = 1; struct rockchip_spi *rs = spi_master_get_devdata(master); WARN_ON(readl_relaxed(rs->regs + ROCKCHIP_SPI_SSIENR) && (readl_relaxed(rs->regs + ROCKCHIP_SPI_SR) & SR_BUSY)); if (!xfer->tx_buf && !xfer->rx_buf) { dev_err(rs->dev, "No buffer for transfer\n"); return -EINVAL; } rs->speed = xfer->speed_hz; rs->bpw = xfer->bits_per_word; rs->n_bytes = rs->bpw >> 3; rs->tx = xfer->tx_buf; rs->tx_end = rs->tx + xfer->len; rs->rx = xfer->rx_buf; rs->rx_end = rs->rx + xfer->len; rs->len = xfer->len; rs->tx_sg = xfer->tx_sg; rs->rx_sg = xfer->rx_sg; if (rs->tx && rs->rx) rs->tmode = CR0_XFM_TR; else if (rs->tx) rs->tmode = CR0_XFM_TO; else if (rs->rx) rs->tmode = CR0_XFM_RO; /* we need prepare dma before spi was enabled */ if (master->can_dma && master->can_dma(master, spi, xfer)) rs->use_dma = 1; else rs->use_dma = 0; rockchip_spi_config(rs); if (rs->use_dma) { if (rs->tmode == CR0_XFM_RO) { /* rx: dma must be prepared first */ rockchip_spi_prepare_dma(rs); spi_enable_chip(rs, 1); } else { /* tx or tr: spi must be enabled first */ spi_enable_chip(rs, 1); rockchip_spi_prepare_dma(rs); } } else { spi_enable_chip(rs, 1); ret = rockchip_spi_pio_transfer(rs); } return ret; }
int dw_spi_add_host(struct device *dev, struct dw_spi *dws) { struct spi_controller *master; int ret; BUG_ON(dws == NULL); master = spi_alloc_master(dev, 0); if (!master) return -ENOMEM; dws->master = master; dws->type = SSI_MOTO_SPI; dws->dma_inited = 0; dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR); spi_controller_set_devdata(master, dws); ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev), master); if (ret < 0) { dev_err(dev, "can not get IRQ\n"); goto err_free_master; } master->use_gpio_descriptors = true; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; master->setup = dw_spi_setup; master->cleanup = dw_spi_cleanup; master->set_cs = dw_spi_set_cs; master->transfer_one = dw_spi_transfer_one; master->handle_err = dw_spi_handle_err; master->max_speed_hz = dws->max_freq; master->dev.of_node = dev->of_node; master->dev.fwnode = dev->fwnode; master->flags = SPI_MASTER_GPIO_SS; if (dws->set_cs) master->set_cs = dws->set_cs; /* Basic HW init */ spi_hw_init(dev, dws); if (dws->dma_ops && dws->dma_ops->dma_init) { ret = dws->dma_ops->dma_init(dws); if (ret) { dev_warn(dev, "DMA init failed\n"); dws->dma_inited = 0; } else { master->can_dma = dws->dma_ops->can_dma; } } ret = devm_spi_register_controller(dev, master); if (ret) { dev_err(&master->dev, "problem registering spi master\n"); goto err_dma_exit; } dw_spi_debugfs_init(dws); return 0; err_dma_exit: if (dws->dma_ops && dws->dma_ops->dma_exit) dws->dma_ops->dma_exit(dws); spi_enable_chip(dws, 0); free_irq(dws->irq, master); err_free_master: spi_controller_put(master); return ret; }
static int dw_spi_transfer_one(struct spi_controller *master, struct spi_device *spi, struct spi_transfer *transfer) { struct dw_spi *dws = spi_controller_get_devdata(master); struct chip_data *chip = spi_get_ctldata(spi); u8 imask = 0; u16 txlevel = 0; u32 cr0; int ret; dws->dma_mapped = 0; dws->tx = (void *)transfer->tx_buf; dws->tx_end = dws->tx + transfer->len; dws->rx = transfer->rx_buf; dws->rx_end = dws->rx + transfer->len; dws->len = transfer->len; spi_enable_chip(dws, 0); /* Handle per transfer options for bpw and speed */ if (transfer->speed_hz != dws->current_freq) { if (transfer->speed_hz != chip->speed_hz) { /* clk_div doesn't support odd number */ chip->clk_div = (DIV_ROUND_UP(dws->max_freq, transfer->speed_hz) + 1) & 0xfffe; chip->speed_hz = transfer->speed_hz; } dws->current_freq = transfer->speed_hz; spi_set_clk(dws, chip->clk_div); } dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); dws->dma_width = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE); /* Default SPI mode is SCPOL = 0, SCPH = 0 */ cr0 = (transfer->bits_per_word - 1) | (chip->type << SPI_FRF_OFFSET) | ((((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET) | (((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET)) | (chip->tmode << SPI_TMOD_OFFSET); /* * Adjust transfer mode if necessary. Requires platform dependent * chipselect mechanism. */ if (chip->cs_control) { if (dws->rx && dws->tx) chip->tmode = SPI_TMOD_TR; else if (dws->rx) chip->tmode = SPI_TMOD_RO; else chip->tmode = SPI_TMOD_TO; cr0 &= ~SPI_TMOD_MASK; cr0 |= (chip->tmode << SPI_TMOD_OFFSET); } dw_writel(dws, DW_SPI_CTRL0, cr0); /* Check if current transfer is a DMA transaction */ if (master->can_dma && master->can_dma(master, spi, transfer)) dws->dma_mapped = master->cur_msg_mapped; /* For poll mode just disable all interrupts */ spi_mask_intr(dws, 0xff); /* * Interrupt mode * we only need set the TXEI IRQ, as TX/RX always happen syncronizely */ if (dws->dma_mapped) { ret = dws->dma_ops->dma_setup(dws, transfer); if (ret < 0) { spi_enable_chip(dws, 1); return ret; } } else if (!chip->poll_mode) { txlevel = min_t(u16, dws->fifo_len / 2, dws->len / dws->n_bytes); dw_writel(dws, DW_SPI_TXFLTR, txlevel); /* Set the interrupt mask */ imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI; spi_umask_intr(dws, imask); dws->transfer_handler = interrupt_transfer; } spi_enable_chip(dws, 1); if (dws->dma_mapped) { ret = dws->dma_ops->dma_transfer(dws, transfer); if (ret < 0) return ret; } if (chip->poll_mode) return poll_transfer(dws); return 1; }