You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'fix/fsl-dspi' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi into spi-fsl-dspi
This commit is contained in:
+2
-3
@@ -159,10 +159,9 @@ config SPI_BUTTERFLY
|
||||
|
||||
config SPI_CADENCE
|
||||
tristate "Cadence SPI controller"
|
||||
depends on ARM
|
||||
help
|
||||
This selects the Cadence SPI controller master driver
|
||||
used by Xilinx Zynq.
|
||||
used by Xilinx Zynq and ZynqMP.
|
||||
|
||||
config SPI_CLPS711X
|
||||
tristate "CLPS711X host SPI controller"
|
||||
@@ -632,7 +631,7 @@ config SPI_DW_PCI
|
||||
|
||||
config SPI_DW_MID_DMA
|
||||
bool "DMA support for DW SPI controller on Intel MID platform"
|
||||
depends on SPI_DW_PCI && INTEL_MID_DMAC
|
||||
depends on SPI_DW_PCI && DW_DMAC_PCI
|
||||
|
||||
config SPI_DW_MMIO
|
||||
tristate "Memory-mapped io interface driver for DW SPI core"
|
||||
|
||||
+13
-7
@@ -180,11 +180,17 @@
|
||||
| SPI_BF(name, value))
|
||||
|
||||
/* Register access macros */
|
||||
#ifdef CONFIG_AVR32
|
||||
#define spi_readl(port, reg) \
|
||||
__raw_readl((port)->regs + SPI_##reg)
|
||||
#define spi_writel(port, reg, value) \
|
||||
__raw_writel((value), (port)->regs + SPI_##reg)
|
||||
|
||||
#else
|
||||
#define spi_readl(port, reg) \
|
||||
readl_relaxed((port)->regs + SPI_##reg)
|
||||
#define spi_writel(port, reg, value) \
|
||||
writel_relaxed((value), (port)->regs + SPI_##reg)
|
||||
#endif
|
||||
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
|
||||
* cache operations; better heuristics consider wordsize and bitrate.
|
||||
*/
|
||||
@@ -764,17 +770,17 @@ static void atmel_spi_pdc_next_xfer(struct spi_master *master,
|
||||
(unsigned long long)xfer->rx_dma);
|
||||
}
|
||||
|
||||
/* REVISIT: We're waiting for ENDRX before we start the next
|
||||
/* REVISIT: We're waiting for RXBUFF before we start the next
|
||||
* transfer because we need to handle some difficult timing
|
||||
* issues otherwise. If we wait for ENDTX in one transfer and
|
||||
* then starts waiting for ENDRX in the next, it's difficult
|
||||
* to tell the difference between the ENDRX interrupt we're
|
||||
* actually waiting for and the ENDRX interrupt of the
|
||||
* issues otherwise. If we wait for TXBUFE in one transfer and
|
||||
* then starts waiting for RXBUFF in the next, it's difficult
|
||||
* to tell the difference between the RXBUFF interrupt we're
|
||||
* actually waiting for and the RXBUFF interrupt of the
|
||||
* previous transfer.
|
||||
*
|
||||
* It should be doable, though. Just not now...
|
||||
*/
|
||||
spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
|
||||
spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES));
|
||||
spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
|
||||
}
|
||||
|
||||
|
||||
+269
-154
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,7 @@ static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms)
|
||||
u32 tmp;
|
||||
|
||||
/* SPE bit has to be 0 before we read MSPI STATUS */
|
||||
deadline = jiffies + BCM53XXSPI_SPE_TIMEOUT_MS * HZ / 1000;
|
||||
deadline = jiffies + msecs_to_jiffies(BCM53XXSPI_SPE_TIMEOUT_MS);
|
||||
do {
|
||||
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_SPCR2);
|
||||
if (!(tmp & B53SPI_MSPI_SPCR2_SPE))
|
||||
@@ -56,7 +56,7 @@ static int bcm53xxspi_wait(struct bcm53xxspi *b53spi, unsigned int timeout_ms)
|
||||
goto spi_timeout;
|
||||
|
||||
/* Check status */
|
||||
deadline = jiffies + timeout_ms * HZ / 1000;
|
||||
deadline = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
do {
|
||||
tmp = bcm53xxspi_read(b53spi, B53SPI_MSPI_MSPI_STATUS);
|
||||
if (tmp & B53SPI_MSPI_MSPI_STATUS_SPIF) {
|
||||
|
||||
@@ -559,7 +559,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
|
||||
struct spi_transfer *previous = NULL;
|
||||
struct bfin_spi_slave_data *chip = NULL;
|
||||
unsigned int bits_per_word;
|
||||
u16 cr, cr_width, dma_width, dma_config;
|
||||
u16 cr, cr_width = 0, dma_width, dma_config;
|
||||
u32 tranf_success = 1;
|
||||
u8 full_duplex = 0;
|
||||
|
||||
@@ -648,7 +648,6 @@ static void bfin_spi_pump_transfers(unsigned long data)
|
||||
} else if (bits_per_word == 8) {
|
||||
drv_data->n_bytes = bits_per_word/8;
|
||||
drv_data->len = transfer->len;
|
||||
cr_width = 0;
|
||||
drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
|
||||
}
|
||||
cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
|
||||
|
||||
@@ -49,12 +49,17 @@ bitbang_txrx_be_cpha0(struct spi_device *spi,
|
||||
{
|
||||
/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
|
||||
|
||||
bool oldbit = !(word & 1);
|
||||
/* clock starts at inactive polarity */
|
||||
for (word <<= (32 - bits); likely(bits); bits--) {
|
||||
|
||||
/* setup MSB (to slave) on trailing edge */
|
||||
if ((flags & SPI_MASTER_NO_TX) == 0)
|
||||
setmosi(spi, word & (1 << 31));
|
||||
if ((flags & SPI_MASTER_NO_TX) == 0) {
|
||||
if ((word & (1 << 31)) != oldbit) {
|
||||
setmosi(spi, word & (1 << 31));
|
||||
oldbit = word & (1 << 31);
|
||||
}
|
||||
}
|
||||
spidelay(nsecs); /* T(setup) */
|
||||
|
||||
setsck(spi, !cpol);
|
||||
@@ -76,13 +81,18 @@ bitbang_txrx_be_cpha1(struct spi_device *spi,
|
||||
{
|
||||
/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
|
||||
|
||||
bool oldbit = !(word & (1 << 31));
|
||||
/* clock starts at inactive polarity */
|
||||
for (word <<= (32 - bits); likely(bits); bits--) {
|
||||
|
||||
/* setup MSB (to slave) on leading edge */
|
||||
setsck(spi, !cpol);
|
||||
if ((flags & SPI_MASTER_NO_TX) == 0)
|
||||
setmosi(spi, word & (1 << 31));
|
||||
if ((flags & SPI_MASTER_NO_TX) == 0) {
|
||||
if ((word & (1 << 31)) != oldbit) {
|
||||
setmosi(spi, word & (1 << 31));
|
||||
oldbit = word & (1 << 31);
|
||||
}
|
||||
}
|
||||
spidelay(nsecs); /* T(setup) */
|
||||
|
||||
setsck(spi, cpol);
|
||||
|
||||
+113
-66
@@ -23,29 +23,31 @@
|
||||
#include "spi-dw.h"
|
||||
|
||||
#ifdef CONFIG_SPI_DW_MID_DMA
|
||||
#include <linux/intel_mid_dma.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_data/dma-dw.h>
|
||||
|
||||
#define RX_BUSY 0
|
||||
#define TX_BUSY 1
|
||||
|
||||
struct mid_dma {
|
||||
struct intel_mid_dma_slave dmas_tx;
|
||||
struct intel_mid_dma_slave dmas_rx;
|
||||
};
|
||||
static struct dw_dma_slave mid_dma_tx = { .dst_id = 1 };
|
||||
static struct dw_dma_slave mid_dma_rx = { .src_id = 0 };
|
||||
|
||||
static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
|
||||
{
|
||||
struct dw_spi *dws = param;
|
||||
struct dw_dma_slave *s = param;
|
||||
|
||||
return dws->dma_dev == chan->device->dev;
|
||||
if (s->dma_dev != chan->device->dev)
|
||||
return false;
|
||||
|
||||
chan->private = s;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int mid_spi_dma_init(struct dw_spi *dws)
|
||||
{
|
||||
struct mid_dma *dw_dma = dws->dma_priv;
|
||||
struct pci_dev *dma_dev;
|
||||
struct intel_mid_dma_slave *rxs, *txs;
|
||||
struct dw_dma_slave *tx = dws->dma_tx;
|
||||
struct dw_dma_slave *rx = dws->dma_rx;
|
||||
dma_cap_mask_t mask;
|
||||
|
||||
/*
|
||||
@@ -56,28 +58,22 @@ static int mid_spi_dma_init(struct dw_spi *dws)
|
||||
if (!dma_dev)
|
||||
return -ENODEV;
|
||||
|
||||
dws->dma_dev = &dma_dev->dev;
|
||||
|
||||
dma_cap_zero(mask);
|
||||
dma_cap_set(DMA_SLAVE, mask);
|
||||
|
||||
/* 1. Init rx channel */
|
||||
dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
|
||||
rx->dma_dev = &dma_dev->dev;
|
||||
dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, rx);
|
||||
if (!dws->rxchan)
|
||||
goto err_exit;
|
||||
rxs = &dw_dma->dmas_rx;
|
||||
rxs->hs_mode = LNW_DMA_HW_HS;
|
||||
rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
|
||||
dws->rxchan->private = rxs;
|
||||
dws->master->dma_rx = dws->rxchan;
|
||||
|
||||
/* 2. Init tx channel */
|
||||
dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
|
||||
tx->dma_dev = &dma_dev->dev;
|
||||
dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, tx);
|
||||
if (!dws->txchan)
|
||||
goto free_rxchan;
|
||||
txs = &dw_dma->dmas_tx;
|
||||
txs->hs_mode = LNW_DMA_HW_HS;
|
||||
txs->cfg_mode = LNW_DMA_MEM_TO_PER;
|
||||
dws->txchan->private = txs;
|
||||
dws->master->dma_tx = dws->txchan;
|
||||
|
||||
dws->dma_inited = 1;
|
||||
return 0;
|
||||
@@ -100,6 +96,42 @@ static void mid_spi_dma_exit(struct dw_spi *dws)
|
||||
dma_release_channel(dws->rxchan);
|
||||
}
|
||||
|
||||
static irqreturn_t dma_transfer(struct dw_spi *dws)
|
||||
{
|
||||
u16 irq_status = dw_readl(dws, DW_SPI_ISR);
|
||||
|
||||
if (!irq_status)
|
||||
return IRQ_NONE;
|
||||
|
||||
dw_readl(dws, DW_SPI_ICR);
|
||||
spi_reset_chip(dws);
|
||||
|
||||
dev_err(&dws->master->dev, "%s: FIFO overrun/underrun\n", __func__);
|
||||
dws->master->cur_msg->status = -EIO;
|
||||
spi_finalize_current_transfer(dws->master);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static bool mid_spi_can_dma(struct spi_master *master, struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct dw_spi *dws = spi_master_get_devdata(master);
|
||||
|
||||
if (!dws->dma_inited)
|
||||
return false;
|
||||
|
||||
return xfer->len > dws->fifo_len;
|
||||
}
|
||||
|
||||
static enum dma_slave_buswidth convert_dma_width(u32 dma_width) {
|
||||
if (dma_width == 1)
|
||||
return DMA_SLAVE_BUSWIDTH_1_BYTE;
|
||||
else if (dma_width == 2)
|
||||
return DMA_SLAVE_BUSWIDTH_2_BYTES;
|
||||
|
||||
return DMA_SLAVE_BUSWIDTH_UNDEFINED;
|
||||
}
|
||||
|
||||
/*
|
||||
* dws->dma_chan_busy is set before the dma transfer starts, callback for tx
|
||||
* channel will clear a corresponding bit.
|
||||
@@ -108,37 +140,38 @@ static void dw_spi_dma_tx_done(void *arg)
|
||||
{
|
||||
struct dw_spi *dws = arg;
|
||||
|
||||
if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY))
|
||||
clear_bit(TX_BUSY, &dws->dma_chan_busy);
|
||||
if (test_bit(RX_BUSY, &dws->dma_chan_busy))
|
||||
return;
|
||||
dw_spi_xfer_done(dws);
|
||||
spi_finalize_current_transfer(dws->master);
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
|
||||
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct dma_slave_config txconf;
|
||||
struct dma_async_tx_descriptor *txdesc;
|
||||
|
||||
if (!dws->tx_dma)
|
||||
if (!xfer->tx_buf)
|
||||
return NULL;
|
||||
|
||||
txconf.direction = DMA_MEM_TO_DEV;
|
||||
txconf.dst_addr = dws->dma_addr;
|
||||
txconf.dst_maxburst = LNW_DMA_MSIZE_16;
|
||||
txconf.dst_maxburst = 16;
|
||||
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
txconf.dst_addr_width = dws->dma_width;
|
||||
txconf.dst_addr_width = convert_dma_width(dws->dma_width);
|
||||
txconf.device_fc = false;
|
||||
|
||||
dmaengine_slave_config(dws->txchan, &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 = dmaengine_prep_slave_sg(dws->txchan,
|
||||
&dws->tx_sgl,
|
||||
1,
|
||||
xfer->tx_sg.sgl,
|
||||
xfer->tx_sg.nents,
|
||||
DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!txdesc)
|
||||
return NULL;
|
||||
|
||||
txdesc->callback = dw_spi_dma_tx_done;
|
||||
txdesc->callback_param = dws;
|
||||
|
||||
@@ -153,74 +186,74 @@ static void dw_spi_dma_rx_done(void *arg)
|
||||
{
|
||||
struct dw_spi *dws = arg;
|
||||
|
||||
if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY))
|
||||
clear_bit(RX_BUSY, &dws->dma_chan_busy);
|
||||
if (test_bit(TX_BUSY, &dws->dma_chan_busy))
|
||||
return;
|
||||
dw_spi_xfer_done(dws);
|
||||
spi_finalize_current_transfer(dws->master);
|
||||
}
|
||||
|
||||
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
|
||||
static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct dma_slave_config rxconf;
|
||||
struct dma_async_tx_descriptor *rxdesc;
|
||||
|
||||
if (!dws->rx_dma)
|
||||
if (!xfer->rx_buf)
|
||||
return NULL;
|
||||
|
||||
rxconf.direction = DMA_DEV_TO_MEM;
|
||||
rxconf.src_addr = dws->dma_addr;
|
||||
rxconf.src_maxburst = LNW_DMA_MSIZE_16;
|
||||
rxconf.src_maxburst = 16;
|
||||
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
|
||||
rxconf.src_addr_width = dws->dma_width;
|
||||
rxconf.src_addr_width = convert_dma_width(dws->dma_width);
|
||||
rxconf.device_fc = false;
|
||||
|
||||
dmaengine_slave_config(dws->rxchan, &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 = dmaengine_prep_slave_sg(dws->rxchan,
|
||||
&dws->rx_sgl,
|
||||
1,
|
||||
xfer->rx_sg.sgl,
|
||||
xfer->rx_sg.nents,
|
||||
DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!rxdesc)
|
||||
return NULL;
|
||||
|
||||
rxdesc->callback = dw_spi_dma_rx_done;
|
||||
rxdesc->callback_param = dws;
|
||||
|
||||
return rxdesc;
|
||||
}
|
||||
|
||||
static void dw_spi_dma_setup(struct dw_spi *dws)
|
||||
static int mid_spi_dma_setup(struct dw_spi *dws, struct spi_transfer *xfer)
|
||||
{
|
||||
u16 dma_ctrl = 0;
|
||||
|
||||
spi_enable_chip(dws, 0);
|
||||
dw_writel(dws, DW_SPI_DMARDLR, 0xf);
|
||||
dw_writel(dws, DW_SPI_DMATDLR, 0x10);
|
||||
|
||||
dw_writew(dws, DW_SPI_DMARDLR, 0xf);
|
||||
dw_writew(dws, DW_SPI_DMATDLR, 0x10);
|
||||
|
||||
if (dws->tx_dma)
|
||||
if (xfer->tx_buf)
|
||||
dma_ctrl |= SPI_DMA_TDMAE;
|
||||
if (dws->rx_dma)
|
||||
if (xfer->rx_buf)
|
||||
dma_ctrl |= SPI_DMA_RDMAE;
|
||||
dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
|
||||
dw_writel(dws, DW_SPI_DMACR, dma_ctrl);
|
||||
|
||||
spi_enable_chip(dws, 1);
|
||||
/* Set the interrupt mask */
|
||||
spi_umask_intr(dws, SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI);
|
||||
|
||||
dws->transfer_handler = dma_transfer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
|
||||
static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)
|
||||
{
|
||||
struct dma_async_tx_descriptor *txdesc, *rxdesc;
|
||||
|
||||
/* 1. setup DMA related registers */
|
||||
if (cs_change)
|
||||
dw_spi_dma_setup(dws);
|
||||
/* Prepare the TX dma transfer */
|
||||
txdesc = dw_spi_dma_prepare_tx(dws, xfer);
|
||||
|
||||
/* 2. Prepare the TX dma transfer */
|
||||
txdesc = dw_spi_dma_prepare_tx(dws);
|
||||
|
||||
/* 3. Prepare the RX dma transfer */
|
||||
rxdesc = dw_spi_dma_prepare_rx(dws);
|
||||
/* Prepare the RX dma transfer */
|
||||
rxdesc = dw_spi_dma_prepare_rx(dws, xfer);
|
||||
|
||||
/* rx must be started before tx due to spi instinct */
|
||||
if (rxdesc) {
|
||||
@@ -238,10 +271,25 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mid_spi_dma_stop(struct dw_spi *dws)
|
||||
{
|
||||
if (test_bit(TX_BUSY, &dws->dma_chan_busy)) {
|
||||
dmaengine_terminate_all(dws->txchan);
|
||||
clear_bit(TX_BUSY, &dws->dma_chan_busy);
|
||||
}
|
||||
if (test_bit(RX_BUSY, &dws->dma_chan_busy)) {
|
||||
dmaengine_terminate_all(dws->rxchan);
|
||||
clear_bit(RX_BUSY, &dws->dma_chan_busy);
|
||||
}
|
||||
}
|
||||
|
||||
static struct dw_spi_dma_ops mid_dma_ops = {
|
||||
.dma_init = mid_spi_dma_init,
|
||||
.dma_exit = mid_spi_dma_exit,
|
||||
.dma_setup = mid_spi_dma_setup,
|
||||
.can_dma = mid_spi_can_dma,
|
||||
.dma_transfer = mid_spi_dma_transfer,
|
||||
.dma_stop = mid_spi_dma_stop,
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -274,9 +322,8 @@ int dw_spi_mid_init(struct dw_spi *dws)
|
||||
iounmap(clk_reg);
|
||||
|
||||
#ifdef CONFIG_SPI_DW_MID_DMA
|
||||
dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL);
|
||||
if (!dws->dma_priv)
|
||||
return -ENOMEM;
|
||||
dws->dma_tx = &mid_dma_tx;
|
||||
dws->dma_rx = &mid_dma_rx;
|
||||
dws->dma_ops = &mid_dma_ops;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
@@ -36,13 +36,13 @@ struct spi_pci_desc {
|
||||
|
||||
static struct spi_pci_desc spi_pci_mid_desc_1 = {
|
||||
.setup = dw_spi_mid_init,
|
||||
.num_cs = 32,
|
||||
.num_cs = 5,
|
||||
.bus_num = 0,
|
||||
};
|
||||
|
||||
static struct spi_pci_desc spi_pci_mid_desc_2 = {
|
||||
.setup = dw_spi_mid_init,
|
||||
.num_cs = 4,
|
||||
.num_cs = 2,
|
||||
.bus_num = 1,
|
||||
};
|
||||
|
||||
|
||||
+94
-216
File diff suppressed because it is too large
Load Diff
+21
-49
@@ -91,12 +91,15 @@ struct dw_spi;
|
||||
struct dw_spi_dma_ops {
|
||||
int (*dma_init)(struct dw_spi *dws);
|
||||
void (*dma_exit)(struct dw_spi *dws);
|
||||
int (*dma_transfer)(struct dw_spi *dws, int cs_change);
|
||||
int (*dma_setup)(struct dw_spi *dws, struct spi_transfer *xfer);
|
||||
bool (*can_dma)(struct spi_master *master, struct spi_device *spi,
|
||||
struct spi_transfer *xfer);
|
||||
int (*dma_transfer)(struct dw_spi *dws, struct spi_transfer *xfer);
|
||||
void (*dma_stop)(struct dw_spi *dws);
|
||||
};
|
||||
|
||||
struct dw_spi {
|
||||
struct spi_master *master;
|
||||
struct spi_device *cur_dev;
|
||||
enum dw_ssi_type type;
|
||||
char name[16];
|
||||
|
||||
@@ -109,41 +112,26 @@ struct dw_spi {
|
||||
u16 bus_num;
|
||||
u16 num_cs; /* supported slave numbers */
|
||||
|
||||
/* Message Transfer pump */
|
||||
struct tasklet_struct pump_transfers;
|
||||
|
||||
/* Current message transfer state info */
|
||||
struct spi_message *cur_msg;
|
||||
struct spi_transfer *cur_transfer;
|
||||
struct chip_data *cur_chip;
|
||||
struct chip_data *prev_chip;
|
||||
size_t len;
|
||||
void *tx;
|
||||
void *tx_end;
|
||||
void *rx;
|
||||
void *rx_end;
|
||||
int dma_mapped;
|
||||
dma_addr_t rx_dma;
|
||||
dma_addr_t tx_dma;
|
||||
size_t rx_map_len;
|
||||
size_t tx_map_len;
|
||||
u8 n_bytes; /* current is a 1/2 bytes op */
|
||||
u8 max_bits_per_word; /* maxim is 16b */
|
||||
u32 dma_width;
|
||||
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
||||
void (*cs_control)(u32 command);
|
||||
|
||||
/* Dma info */
|
||||
/* DMA info */
|
||||
int dma_inited;
|
||||
struct dma_chan *txchan;
|
||||
struct scatterlist tx_sgl;
|
||||
struct dma_chan *rxchan;
|
||||
struct scatterlist rx_sgl;
|
||||
unsigned long dma_chan_busy;
|
||||
struct device *dma_dev;
|
||||
dma_addr_t dma_addr; /* phy address of the Data register */
|
||||
struct dw_spi_dma_ops *dma_ops;
|
||||
void *dma_priv; /* platform relate info */
|
||||
void *dma_tx;
|
||||
void *dma_rx;
|
||||
|
||||
/* Bus interface info */
|
||||
void *priv;
|
||||
@@ -162,16 +150,6 @@ static inline void dw_writel(struct dw_spi *dws, u32 offset, u32 val)
|
||||
__raw_writel(val, dws->regs + offset);
|
||||
}
|
||||
|
||||
static inline u16 dw_readw(struct dw_spi *dws, u32 offset)
|
||||
{
|
||||
return __raw_readw(dws->regs + offset);
|
||||
}
|
||||
|
||||
static inline void dw_writew(struct dw_spi *dws, u32 offset, u16 val)
|
||||
{
|
||||
__raw_writew(val, dws->regs + offset);
|
||||
}
|
||||
|
||||
static inline void spi_enable_chip(struct dw_spi *dws, int enable)
|
||||
{
|
||||
dw_writel(dws, DW_SPI_SSIENR, (enable ? 1 : 0));
|
||||
@@ -182,22 +160,6 @@ static inline void spi_set_clk(struct dw_spi *dws, u16 div)
|
||||
dw_writel(dws, DW_SPI_BAUDR, div);
|
||||
}
|
||||
|
||||
static inline void spi_chip_sel(struct dw_spi *dws, struct spi_device *spi,
|
||||
int active)
|
||||
{
|
||||
u16 cs = spi->chip_select;
|
||||
int gpio_val = active ? (spi->mode & SPI_CS_HIGH) :
|
||||
!(spi->mode & SPI_CS_HIGH);
|
||||
|
||||
if (dws->cs_control)
|
||||
dws->cs_control(active);
|
||||
if (gpio_is_valid(spi->cs_gpio))
|
||||
gpio_set_value(spi->cs_gpio, gpio_val);
|
||||
|
||||
if (active)
|
||||
dw_writel(dws, DW_SPI_SER, 1 << cs);
|
||||
}
|
||||
|
||||
/* Disable IRQ bits */
|
||||
static inline void spi_mask_intr(struct dw_spi *dws, u32 mask)
|
||||
{
|
||||
@@ -216,16 +178,27 @@ static inline void spi_umask_intr(struct dw_spi *dws, u32 mask)
|
||||
dw_writel(dws, DW_SPI_IMR, new_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* This does disable the SPI controller, interrupts, and re-enable the
|
||||
* controller back. Transmit and receive FIFO buffers are cleared when the
|
||||
* device is disabled.
|
||||
*/
|
||||
static inline void spi_reset_chip(struct dw_spi *dws)
|
||||
{
|
||||
spi_enable_chip(dws, 0);
|
||||
spi_mask_intr(dws, 0xff);
|
||||
spi_enable_chip(dws, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Each SPI slave device to work with dw_api controller should
|
||||
* has such a structure claiming its working mode (PIO/DMA etc),
|
||||
* has such a structure claiming its working mode (poll or PIO/DMA),
|
||||
* which can be save in the "controller_data" member of the
|
||||
* struct spi_device.
|
||||
*/
|
||||
struct dw_spi_chip {
|
||||
u8 poll_mode; /* 1 for controller polling mode */
|
||||
u8 type; /* SPI/SSP/MicroWire */
|
||||
u8 enable_dma;
|
||||
void (*cs_control)(u32 command);
|
||||
};
|
||||
|
||||
@@ -233,7 +206,6 @@ extern int dw_spi_add_host(struct device *dev, struct dw_spi *dws);
|
||||
extern void dw_spi_remove_host(struct dw_spi *dws);
|
||||
extern int dw_spi_suspend_host(struct dw_spi *dws);
|
||||
extern int dw_spi_resume_host(struct dw_spi *dws);
|
||||
extern void dw_spi_xfer_done(struct dw_spi *dws);
|
||||
|
||||
/* platform related setup */
|
||||
extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */
|
||||
|
||||
+83
-18
@@ -20,6 +20,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
@@ -29,6 +30,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/spi/spi_bitbang.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#define DRIVER_NAME "fsl-dspi"
|
||||
|
||||
@@ -51,7 +53,7 @@
|
||||
#define SPI_CTAR_CPOL(x) ((x) << 26)
|
||||
#define SPI_CTAR_CPHA(x) ((x) << 25)
|
||||
#define SPI_CTAR_LSBFE(x) ((x) << 24)
|
||||
#define SPI_CTAR_PCSSCR(x) (((x) & 0x00000003) << 22)
|
||||
#define SPI_CTAR_PCSSCK(x) (((x) & 0x00000003) << 22)
|
||||
#define SPI_CTAR_PASC(x) (((x) & 0x00000003) << 20)
|
||||
#define SPI_CTAR_PDT(x) (((x) & 0x00000003) << 18)
|
||||
#define SPI_CTAR_PBR(x) (((x) & 0x00000003) << 16)
|
||||
@@ -59,6 +61,7 @@
|
||||
#define SPI_CTAR_ASC(x) (((x) & 0x0000000f) << 8)
|
||||
#define SPI_CTAR_DT(x) (((x) & 0x0000000f) << 4)
|
||||
#define SPI_CTAR_BR(x) ((x) & 0x0000000f)
|
||||
#define SPI_CTAR_SCALE_BITS 0xf
|
||||
|
||||
#define SPI_CTAR0_SLAVE 0x0c
|
||||
|
||||
@@ -148,23 +151,66 @@ static void hz_to_spi_baud(char *pbr, char *br, int speed_hz,
|
||||
16, 32, 64, 128,
|
||||
256, 512, 1024, 2048,
|
||||
4096, 8192, 16384, 32768 };
|
||||
int temp, i = 0, j = 0;
|
||||
int scale_needed, scale, minscale = INT_MAX;
|
||||
int i, j;
|
||||
|
||||
temp = clkrate / 2 / speed_hz;
|
||||
scale_needed = clkrate / speed_hz;
|
||||
if (clkrate % speed_hz)
|
||||
scale_needed++;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pbr_tbl); i++)
|
||||
for (j = 0; j < ARRAY_SIZE(brs); j++) {
|
||||
if (pbr_tbl[i] * brs[j] >= temp) {
|
||||
*pbr = i;
|
||||
*br = j;
|
||||
return;
|
||||
for (i = 0; i < ARRAY_SIZE(brs); i++)
|
||||
for (j = 0; j < ARRAY_SIZE(pbr_tbl); j++) {
|
||||
scale = brs[i] * pbr_tbl[j];
|
||||
if (scale >= scale_needed) {
|
||||
if (scale < minscale) {
|
||||
minscale = scale;
|
||||
*br = i;
|
||||
*pbr = j;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld\
|
||||
,we use the max prescaler value.\n", speed_hz, clkrate);
|
||||
*pbr = ARRAY_SIZE(pbr_tbl) - 1;
|
||||
*br = ARRAY_SIZE(brs) - 1;
|
||||
if (minscale == INT_MAX) {
|
||||
pr_warn("Can not find valid baud rate,speed_hz is %d,clkrate is %ld, we use the max prescaler value.\n",
|
||||
speed_hz, clkrate);
|
||||
*pbr = ARRAY_SIZE(pbr_tbl) - 1;
|
||||
*br = ARRAY_SIZE(brs) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ns_delay_scale(char *psc, char *sc, int delay_ns,
|
||||
unsigned long clkrate)
|
||||
{
|
||||
int pscale_tbl[4] = {1, 3, 5, 7};
|
||||
int scale_needed, scale, minscale = INT_MAX;
|
||||
int i, j;
|
||||
u32 remainder;
|
||||
|
||||
scale_needed = div_u64_rem((u64)delay_ns * clkrate, NSEC_PER_SEC,
|
||||
&remainder);
|
||||
if (remainder)
|
||||
scale_needed++;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(pscale_tbl); i++)
|
||||
for (j = 0; j <= SPI_CTAR_SCALE_BITS; j++) {
|
||||
scale = pscale_tbl[i] * (2 << j);
|
||||
if (scale >= scale_needed) {
|
||||
if (scale < minscale) {
|
||||
minscale = scale;
|
||||
*psc = i;
|
||||
*sc = j;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (minscale == INT_MAX) {
|
||||
pr_warn("Cannot find correct scale values for %dns delay at clkrate %ld, using max prescaler value",
|
||||
delay_ns, clkrate);
|
||||
*psc = ARRAY_SIZE(pscale_tbl) - 1;
|
||||
*sc = SPI_CTAR_SCALE_BITS;
|
||||
}
|
||||
}
|
||||
|
||||
static int dspi_transfer_write(struct fsl_dspi *dspi)
|
||||
@@ -295,10 +341,10 @@ static int dspi_transfer_one_message(struct spi_master *master,
|
||||
dspi->cur_msg = message;
|
||||
dspi->cur_chip = spi_get_ctldata(spi);
|
||||
dspi->cs = spi->chip_select;
|
||||
dspi->cs_change = 0;
|
||||
if (dspi->cur_transfer->transfer_list.next
|
||||
== &dspi->cur_msg->transfers)
|
||||
transfer->cs_change = 1;
|
||||
dspi->cs_change = transfer->cs_change;
|
||||
dspi->cs_change = 1;
|
||||
dspi->void_write_data = dspi->cur_chip->void_write_data;
|
||||
|
||||
dspi->dataflags = 0;
|
||||
@@ -345,7 +391,10 @@ static int dspi_setup(struct spi_device *spi)
|
||||
{
|
||||
struct chip_data *chip;
|
||||
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
|
||||
unsigned char br = 0, pbr = 0, fmsz = 0;
|
||||
u32 cs_sck_delay = 0, sck_cs_delay = 0;
|
||||
unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
|
||||
unsigned char pasc = 0, asc = 0, fmsz = 0;
|
||||
unsigned long clkrate;
|
||||
|
||||
if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
|
||||
fmsz = spi->bits_per_word - 1;
|
||||
@@ -362,18 +411,34 @@ static int dspi_setup(struct spi_device *spi)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
of_property_read_u32(spi->dev.of_node, "fsl,spi-cs-sck-delay",
|
||||
&cs_sck_delay);
|
||||
|
||||
of_property_read_u32(spi->dev.of_node, "fsl,spi-sck-cs-delay",
|
||||
&sck_cs_delay);
|
||||
|
||||
chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
|
||||
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
|
||||
|
||||
chip->void_write_data = 0;
|
||||
|
||||
hz_to_spi_baud(&pbr, &br,
|
||||
spi->max_speed_hz, clk_get_rate(dspi->clk));
|
||||
clkrate = clk_get_rate(dspi->clk);
|
||||
hz_to_spi_baud(&pbr, &br, spi->max_speed_hz, clkrate);
|
||||
|
||||
/* Set PCS to SCK delay scale values */
|
||||
ns_delay_scale(&pcssck, &cssck, cs_sck_delay, clkrate);
|
||||
|
||||
/* Set After SCK delay scale values */
|
||||
ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
|
||||
|
||||
chip->ctar_val = SPI_CTAR_FMSZ(fmsz)
|
||||
| SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
|
||||
| SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
|
||||
| SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
|
||||
| SPI_CTAR_PCSSCK(pcssck)
|
||||
| SPI_CTAR_CSSCK(cssck)
|
||||
| SPI_CTAR_PASC(pasc)
|
||||
| SPI_CTAR_ASC(asc)
|
||||
| SPI_CTAR_PBR(pbr)
|
||||
| SPI_CTAR_BR(br);
|
||||
|
||||
|
||||
+110
-86
@@ -12,6 +12,7 @@
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
@@ -122,36 +123,31 @@ static inline void spfi_start(struct img_spfi *spfi)
|
||||
spfi_writel(spfi, val, SPFI_CONTROL);
|
||||
}
|
||||
|
||||
static inline void spfi_stop(struct img_spfi *spfi)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = spfi_readl(spfi, SPFI_CONTROL);
|
||||
val &= ~SPFI_CONTROL_SPFI_EN;
|
||||
spfi_writel(spfi, val, SPFI_CONTROL);
|
||||
}
|
||||
|
||||
static inline void spfi_reset(struct img_spfi *spfi)
|
||||
{
|
||||
spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL);
|
||||
udelay(1);
|
||||
spfi_writel(spfi, 0, SPFI_CONTROL);
|
||||
}
|
||||
|
||||
static void spfi_flush_tx_fifo(struct img_spfi *spfi)
|
||||
static int spfi_wait_all_done(struct img_spfi *spfi)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(10);
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(50);
|
||||
|
||||
spfi_writel(spfi, SPFI_INTERRUPT_SDE, SPFI_INTERRUPT_CLEAR);
|
||||
while (time_before(jiffies, timeout)) {
|
||||
if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) &
|
||||
SPFI_INTERRUPT_SDE)
|
||||
return;
|
||||
u32 status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
|
||||
|
||||
if (status & SPFI_INTERRUPT_ALLDONETRIG) {
|
||||
spfi_writel(spfi, SPFI_INTERRUPT_ALLDONETRIG,
|
||||
SPFI_INTERRUPT_CLEAR);
|
||||
return 0;
|
||||
}
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
dev_err(spfi->dev, "Timed out waiting for FIFO to drain\n");
|
||||
dev_err(spfi->dev, "Timed out waiting for transaction to complete\n");
|
||||
spfi_reset(spfi);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf,
|
||||
@@ -237,6 +233,7 @@ static int img_spfi_start_pio(struct spi_master *master,
|
||||
const void *tx_buf = xfer->tx_buf;
|
||||
void *rx_buf = xfer->rx_buf;
|
||||
unsigned long timeout;
|
||||
int ret;
|
||||
|
||||
if (tx_buf)
|
||||
tx_bytes = xfer->len;
|
||||
@@ -269,16 +266,15 @@ static int img_spfi_start_pio(struct spi_master *master,
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
ret = spfi_wait_all_done(spfi);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (rx_bytes > 0 || tx_bytes > 0) {
|
||||
dev_err(spfi->dev, "PIO transfer timed out\n");
|
||||
spfi_reset(spfi);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
if (tx_buf)
|
||||
spfi_flush_tx_fifo(spfi);
|
||||
spfi_stop(spfi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -287,14 +283,12 @@ static void img_spfi_dma_rx_cb(void *data)
|
||||
struct img_spfi *spfi = data;
|
||||
unsigned long flags;
|
||||
|
||||
spfi_wait_all_done(spfi);
|
||||
|
||||
spin_lock_irqsave(&spfi->lock, flags);
|
||||
|
||||
spfi->rx_dma_busy = false;
|
||||
if (!spfi->tx_dma_busy) {
|
||||
spfi_stop(spfi);
|
||||
if (!spfi->tx_dma_busy)
|
||||
spi_finalize_current_transfer(spfi->master);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&spfi->lock, flags);
|
||||
}
|
||||
|
||||
@@ -303,16 +297,12 @@ static void img_spfi_dma_tx_cb(void *data)
|
||||
struct img_spfi *spfi = data;
|
||||
unsigned long flags;
|
||||
|
||||
spfi_flush_tx_fifo(spfi);
|
||||
spfi_wait_all_done(spfi);
|
||||
|
||||
spin_lock_irqsave(&spfi->lock, flags);
|
||||
|
||||
spfi->tx_dma_busy = false;
|
||||
if (!spfi->rx_dma_busy) {
|
||||
spfi_stop(spfi);
|
||||
if (!spfi->rx_dma_busy)
|
||||
spi_finalize_current_transfer(spfi->master);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&spfi->lock, flags);
|
||||
}
|
||||
|
||||
@@ -397,6 +387,75 @@ stop_dma:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void img_spfi_handle_err(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct img_spfi *spfi = spi_master_get_devdata(master);
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Stop all DMA and reset the controller if the previous transaction
|
||||
* timed-out and never completed it's DMA.
|
||||
*/
|
||||
spin_lock_irqsave(&spfi->lock, flags);
|
||||
if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
|
||||
spfi->tx_dma_busy = false;
|
||||
spfi->rx_dma_busy = false;
|
||||
|
||||
dmaengine_terminate_all(spfi->tx_ch);
|
||||
dmaengine_terminate_all(spfi->rx_ch);
|
||||
}
|
||||
spin_unlock_irqrestore(&spfi->lock, flags);
|
||||
}
|
||||
|
||||
static int img_spfi_prepare(struct spi_master *master, struct spi_message *msg)
|
||||
{
|
||||
struct img_spfi *spfi = spi_master_get_devdata(master);
|
||||
u32 val;
|
||||
|
||||
val = spfi_readl(spfi, SPFI_PORT_STATE);
|
||||
if (msg->spi->mode & SPI_CPHA)
|
||||
val |= SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
|
||||
else
|
||||
val &= ~SPFI_PORT_STATE_CK_PHASE(msg->spi->chip_select);
|
||||
if (msg->spi->mode & SPI_CPOL)
|
||||
val |= SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
|
||||
else
|
||||
val &= ~SPFI_PORT_STATE_CK_POL(msg->spi->chip_select);
|
||||
spfi_writel(spfi, val, SPFI_PORT_STATE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int img_spfi_unprepare(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
struct img_spfi *spfi = spi_master_get_devdata(master);
|
||||
|
||||
spfi_reset(spfi);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int img_spfi_setup(struct spi_device *spi)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = gpio_request_one(spi->cs_gpio, (spi->mode & SPI_CS_HIGH) ?
|
||||
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
|
||||
dev_name(&spi->dev));
|
||||
if (ret)
|
||||
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
|
||||
spi->cs_gpio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void img_spfi_cleanup(struct spi_device *spi)
|
||||
{
|
||||
gpio_free(spi->cs_gpio);
|
||||
}
|
||||
|
||||
static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
@@ -405,10 +464,10 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
|
||||
|
||||
/*
|
||||
* output = spfi_clk * (BITCLK / 512), where BITCLK must be a
|
||||
* power of 2 up to 256 (where 255 == 256 since BITCLK is 8 bits)
|
||||
* power of 2 up to 128
|
||||
*/
|
||||
div = DIV_ROUND_UP(master->max_speed_hz, xfer->speed_hz);
|
||||
div = clamp(512 / (1 << get_count_order(div)), 1, 255);
|
||||
div = DIV_ROUND_UP(clk_get_rate(spfi->spfi_clk), xfer->speed_hz);
|
||||
div = clamp(512 / (1 << get_count_order(div)), 1, 128);
|
||||
|
||||
val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select));
|
||||
val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK <<
|
||||
@@ -416,6 +475,9 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
|
||||
val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT;
|
||||
spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select));
|
||||
|
||||
spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
|
||||
SPFI_TRANSACTION);
|
||||
|
||||
val = spfi_readl(spfi, SPFI_CONTROL);
|
||||
val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA);
|
||||
if (xfer->tx_buf)
|
||||
@@ -429,25 +491,7 @@ static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
|
||||
else if (xfer->tx_nbits == SPI_NBITS_QUAD &&
|
||||
xfer->rx_nbits == SPI_NBITS_QUAD)
|
||||
val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT;
|
||||
val &= ~SPFI_CONTROL_CONTINUE;
|
||||
if (!xfer->cs_change && !list_is_last(&xfer->transfer_list,
|
||||
&master->cur_msg->transfers))
|
||||
val |= SPFI_CONTROL_CONTINUE;
|
||||
spfi_writel(spfi, val, SPFI_CONTROL);
|
||||
|
||||
val = spfi_readl(spfi, SPFI_PORT_STATE);
|
||||
if (spi->mode & SPI_CPHA)
|
||||
val |= SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
|
||||
else
|
||||
val &= ~SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
|
||||
if (spi->mode & SPI_CPOL)
|
||||
val |= SPFI_PORT_STATE_CK_POL(spi->chip_select);
|
||||
else
|
||||
val &= ~SPFI_PORT_STATE_CK_POL(spi->chip_select);
|
||||
spfi_writel(spfi, val, SPFI_PORT_STATE);
|
||||
|
||||
spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
|
||||
SPFI_TRANSACTION);
|
||||
}
|
||||
|
||||
static int img_spfi_transfer_one(struct spi_master *master,
|
||||
@@ -455,25 +499,13 @@ static int img_spfi_transfer_one(struct spi_master *master,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct img_spfi *spfi = spi_master_get_devdata(spi->master);
|
||||
bool dma_reset = false;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Stop all DMA and reset the controller if the previous transaction
|
||||
* timed-out and never completed it's DMA.
|
||||
*/
|
||||
spin_lock_irqsave(&spfi->lock, flags);
|
||||
if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
|
||||
dev_err(spfi->dev, "SPI DMA still busy\n");
|
||||
dma_reset = true;
|
||||
}
|
||||
spin_unlock_irqrestore(&spfi->lock, flags);
|
||||
|
||||
if (dma_reset) {
|
||||
dmaengine_terminate_all(spfi->tx_ch);
|
||||
dmaengine_terminate_all(spfi->rx_ch);
|
||||
spfi_reset(spfi);
|
||||
if (xfer->len > SPFI_TRANSACTION_TSIZE_MASK) {
|
||||
dev_err(spfi->dev,
|
||||
"Transfer length (%d) is greater than the max supported (%d)",
|
||||
xfer->len, SPFI_TRANSACTION_TSIZE_MASK);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
img_spfi_config(master, spi, xfer);
|
||||
@@ -485,17 +517,6 @@ static int img_spfi_transfer_one(struct spi_master *master,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void img_spfi_set_cs(struct spi_device *spi, bool enable)
|
||||
{
|
||||
struct img_spfi *spfi = spi_master_get_devdata(spi->master);
|
||||
u32 val;
|
||||
|
||||
val = spfi_readl(spfi, SPFI_PORT_STATE);
|
||||
val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << SPFI_PORT_STATE_DEV_SEL_SHIFT);
|
||||
val |= spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
|
||||
spfi_writel(spfi, val, SPFI_PORT_STATE);
|
||||
}
|
||||
|
||||
static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
@@ -584,14 +605,17 @@ static int img_spfi_probe(struct platform_device *pdev)
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
|
||||
if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode"))
|
||||
master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
|
||||
master->num_chipselect = 5;
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
|
||||
master->max_speed_hz = clk_get_rate(spfi->spfi_clk);
|
||||
master->min_speed_hz = master->max_speed_hz / 512;
|
||||
master->max_speed_hz = clk_get_rate(spfi->spfi_clk) / 4;
|
||||
master->min_speed_hz = clk_get_rate(spfi->spfi_clk) / 512;
|
||||
|
||||
master->set_cs = img_spfi_set_cs;
|
||||
master->setup = img_spfi_setup;
|
||||
master->cleanup = img_spfi_cleanup;
|
||||
master->transfer_one = img_spfi_transfer_one;
|
||||
master->prepare_message = img_spfi_prepare;
|
||||
master->unprepare_message = img_spfi_unprepare;
|
||||
master->handle_err = img_spfi_handle_err;
|
||||
|
||||
spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx");
|
||||
spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx");
|
||||
|
||||
@@ -370,8 +370,6 @@ static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
|
||||
if (spi_imx->dma_is_inited) {
|
||||
dma = readl(spi_imx->base + MX51_ECSPI_DMA);
|
||||
|
||||
spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
spi_imx->rxt_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
rx_wml_cfg = spi_imx->rx_wml << MX51_ECSPI_DMA_RX_WML_OFFSET;
|
||||
tx_wml_cfg = spi_imx->tx_wml << MX51_ECSPI_DMA_TX_WML_OFFSET;
|
||||
@@ -868,6 +866,8 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
|
||||
master->max_dma_len = MAX_SDMA_BD_BYTES;
|
||||
spi_imx->bitbang.master->flags = SPI_MASTER_MUST_RX |
|
||||
SPI_MASTER_MUST_TX;
|
||||
spi_imx->tx_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
spi_imx->rx_wml = spi_imx_get_fifosize(spi_imx) / 2;
|
||||
spi_imx->dma_is_inited = 1;
|
||||
|
||||
return 0;
|
||||
@@ -903,7 +903,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
|
||||
|
||||
if (tx) {
|
||||
desc_tx = dmaengine_prep_slave_sg(master->dma_tx,
|
||||
tx->sgl, tx->nents, DMA_TO_DEVICE,
|
||||
tx->sgl, tx->nents, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc_tx)
|
||||
goto no_dma;
|
||||
@@ -915,7 +915,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
|
||||
|
||||
if (rx) {
|
||||
desc_rx = dmaengine_prep_slave_sg(master->dma_rx,
|
||||
rx->sgl, rx->nents, DMA_FROM_DEVICE,
|
||||
rx->sgl, rx->nents, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!desc_rx)
|
||||
goto no_dma;
|
||||
|
||||
@@ -588,7 +588,7 @@ static int mpc512x_psc_spi_of_remove(struct platform_device *op)
|
||||
return mpc512x_psc_spi_do_remove(&op->dev);
|
||||
}
|
||||
|
||||
static struct of_device_id mpc512x_psc_spi_of_match[] = {
|
||||
static const struct of_device_id mpc512x_psc_spi_of_match[] = {
|
||||
{ .compatible = "fsl,mpc5121-psc-spi", },
|
||||
{},
|
||||
};
|
||||
|
||||
@@ -238,7 +238,7 @@ static int octeon_spi_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct of_device_id octeon_spi_match[] = {
|
||||
static const struct of_device_id octeon_spi_match[] = {
|
||||
{ .compatible = "cavium,octeon-3010-spi", },
|
||||
{},
|
||||
};
|
||||
|
||||
+77
-24
@@ -24,6 +24,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
@@ -294,16 +295,6 @@ static int omap1_spi100k_setup(struct spi_device *spi)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_prepare_hardware(struct spi_master *master)
|
||||
{
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
clk_prepare_enable(spi100k->ick);
|
||||
clk_prepare_enable(spi100k->fck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_transfer_one_message(struct spi_master *master,
|
||||
struct spi_message *m)
|
||||
{
|
||||
@@ -372,16 +363,6 @@ static int omap1_spi100k_transfer_one_message(struct spi_master *master,
|
||||
return status;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_unprepare_hardware(struct spi_master *master)
|
||||
{
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master;
|
||||
@@ -402,14 +383,12 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
|
||||
|
||||
master->setup = omap1_spi100k_setup;
|
||||
master->transfer_one_message = omap1_spi100k_transfer_one_message;
|
||||
master->prepare_transfer_hardware = omap1_spi100k_prepare_hardware;
|
||||
master->unprepare_transfer_hardware = omap1_spi100k_unprepare_hardware;
|
||||
master->cleanup = NULL;
|
||||
master->num_chipselect = 2;
|
||||
master->mode_bits = MODEBITS;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
|
||||
master->min_speed_hz = OMAP1_SPI100K_MAX_FREQ/(1<<16);
|
||||
master->max_speed_hz = OMAP1_SPI100K_MAX_FREQ;
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
spi100k = spi_master_get_devdata(master);
|
||||
|
||||
@@ -434,22 +413,96 @@ static int omap1_spi100k_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = clk_prepare_enable(spi100k->ick);
|
||||
if (status != 0) {
|
||||
dev_err(&pdev->dev, "failed to enable ick: %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = clk_prepare_enable(spi100k->fck);
|
||||
if (status != 0) {
|
||||
dev_err(&pdev->dev, "failed to enable fck: %d\n", status);
|
||||
goto err_ick;
|
||||
}
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
|
||||
status = devm_spi_register_master(&pdev->dev, master);
|
||||
if (status < 0)
|
||||
goto err;
|
||||
goto err_fck;
|
||||
|
||||
return status;
|
||||
|
||||
err_fck:
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
err_ick:
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
err:
|
||||
spi_master_put(master);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int omap1_spi100k_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
clk_disable_unprepare(spi100k->fck);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int omap1_spi100k_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = spi_master_get(dev_get_drvdata(dev));
|
||||
struct omap1_spi100k *spi100k = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(spi100k->ick);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to enable ick: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(spi100k->fck);
|
||||
if (ret != 0) {
|
||||
dev_err(dev, "Failed to enable fck: %d\n", ret);
|
||||
clk_disable_unprepare(spi100k->ick);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct dev_pm_ops omap1_spi100k_pm = {
|
||||
SET_RUNTIME_PM_OPS(omap1_spi100k_runtime_suspend,
|
||||
omap1_spi100k_runtime_resume, NULL)
|
||||
};
|
||||
|
||||
static struct platform_driver omap1_spi100k_driver = {
|
||||
.driver = {
|
||||
.name = "omap1_spi100k",
|
||||
.pm = &omap1_spi100k_pm,
|
||||
},
|
||||
.probe = omap1_spi100k_probe,
|
||||
.remove = omap1_spi100k_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(omap1_spi100k_driver);
|
||||
|
||||
@@ -44,7 +44,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <mach/hardware.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
||||
|
||||
@@ -285,7 +285,12 @@
|
||||
*/
|
||||
#define DEFAULT_SSP_REG_IMSC 0x0UL
|
||||
#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC
|
||||
#define ENABLE_ALL_INTERRUPTS (~DEFAULT_SSP_REG_IMSC)
|
||||
#define ENABLE_ALL_INTERRUPTS ( \
|
||||
SSP_IMSC_MASK_RORIM | \
|
||||
SSP_IMSC_MASK_RTIM | \
|
||||
SSP_IMSC_MASK_RXIM | \
|
||||
SSP_IMSC_MASK_TXIM \
|
||||
)
|
||||
|
||||
#define CLEAR_ALL_INTERRUPTS 0x3
|
||||
|
||||
@@ -534,12 +539,12 @@ static void giveback(struct pl022 *pl022)
|
||||
pl022->cur_msg = NULL;
|
||||
pl022->cur_transfer = NULL;
|
||||
pl022->cur_chip = NULL;
|
||||
spi_finalize_current_message(pl022->master);
|
||||
|
||||
/* disable the SPI/SSP operation */
|
||||
writew((readw(SSP_CR1(pl022->virtbase)) &
|
||||
(~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase));
|
||||
|
||||
spi_finalize_current_message(pl022->master);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1251,7 +1256,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
|
||||
struct pl022 *pl022 = dev_id;
|
||||
struct spi_message *msg = pl022->cur_msg;
|
||||
u16 irq_status = 0;
|
||||
u16 flag = 0;
|
||||
|
||||
if (unlikely(!msg)) {
|
||||
dev_err(&pl022->adev->dev,
|
||||
@@ -1280,9 +1284,6 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
|
||||
if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF)
|
||||
dev_err(&pl022->adev->dev,
|
||||
"RXFIFO is full\n");
|
||||
if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_TNF)
|
||||
dev_err(&pl022->adev->dev,
|
||||
"TXFIFO is full\n");
|
||||
|
||||
/*
|
||||
* Disable and clear interrupts, disable SSP,
|
||||
@@ -1303,8 +1304,7 @@ static irqreturn_t pl022_interrupt_handler(int irq, void *dev_id)
|
||||
|
||||
readwriter(pl022);
|
||||
|
||||
if ((pl022->tx == pl022->tx_end) && (flag == 0)) {
|
||||
flag = 1;
|
||||
if (pl022->tx == pl022->tx_end) {
|
||||
/* Disable Transmit interrupt, enable receive interrupt */
|
||||
writew((readw(SSP_IMSC(pl022->virtbase)) &
|
||||
~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM,
|
||||
|
||||
+121
-71
@@ -20,6 +20,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/pxa2xx_spi.h>
|
||||
#include <linux/spi/spi.h>
|
||||
@@ -30,10 +31,6 @@
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/delay.h>
|
||||
|
||||
#include "spi-pxa2xx.h"
|
||||
|
||||
MODULE_AUTHOR("Stephen Street");
|
||||
@@ -67,54 +64,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
|
||||
#define LPSS_TX_LOTHRESH_DFLT 160
|
||||
#define LPSS_TX_HITHRESH_DFLT 224
|
||||
|
||||
struct quark_spi_rate {
|
||||
u32 bitrate;
|
||||
u32 dds_clk_rate;
|
||||
u32 clk_div;
|
||||
};
|
||||
|
||||
/*
|
||||
* 'rate', 'dds', 'clk_div' lookup table, which is defined in
|
||||
* the Quark SPI datasheet.
|
||||
*/
|
||||
static const struct quark_spi_rate quark_spi_rate_table[] = {
|
||||
/* bitrate, dds_clk_rate, clk_div */
|
||||
{50000000, 0x800000, 0},
|
||||
{40000000, 0x666666, 0},
|
||||
{25000000, 0x400000, 0},
|
||||
{20000000, 0x666666, 1},
|
||||
{16667000, 0x800000, 2},
|
||||
{13333000, 0x666666, 2},
|
||||
{12500000, 0x200000, 0},
|
||||
{10000000, 0x800000, 4},
|
||||
{8000000, 0x666666, 4},
|
||||
{6250000, 0x400000, 3},
|
||||
{5000000, 0x400000, 4},
|
||||
{4000000, 0x666666, 9},
|
||||
{3125000, 0x80000, 0},
|
||||
{2500000, 0x400000, 9},
|
||||
{2000000, 0x666666, 19},
|
||||
{1563000, 0x40000, 0},
|
||||
{1250000, 0x200000, 9},
|
||||
{1000000, 0x400000, 24},
|
||||
{800000, 0x666666, 49},
|
||||
{781250, 0x20000, 0},
|
||||
{625000, 0x200000, 19},
|
||||
{500000, 0x400000, 49},
|
||||
{400000, 0x666666, 99},
|
||||
{390625, 0x10000, 0},
|
||||
{250000, 0x400000, 99},
|
||||
{200000, 0x666666, 199},
|
||||
{195313, 0x8000, 0},
|
||||
{125000, 0x100000, 49},
|
||||
{100000, 0x200000, 124},
|
||||
{50000, 0x100000, 124},
|
||||
{25000, 0x80000, 124},
|
||||
{10016, 0x20000, 77},
|
||||
{5040, 0x20000, 154},
|
||||
{1002, 0x8000, 194},
|
||||
};
|
||||
|
||||
/* Offset from drv_data->lpss_base */
|
||||
#define GENERAL_REG 0x08
|
||||
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
|
||||
@@ -701,25 +650,124 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
|
||||
}
|
||||
|
||||
/*
|
||||
* The Quark SPI data sheet gives a table, and for the given 'rate',
|
||||
* the 'dds' and 'clk_div' can be found in the table.
|
||||
* The Quark SPI has an additional 24 bit register (DDS_CLK_RATE) to multiply
|
||||
* input frequency by fractions of 2^24. It also has a divider by 5.
|
||||
*
|
||||
* There are formulas to get baud rate value for given input frequency and
|
||||
* divider parameters, such as DDS_CLK_RATE and SCR:
|
||||
*
|
||||
* Fsys = 200MHz
|
||||
*
|
||||
* Fssp = Fsys * DDS_CLK_RATE / 2^24 (1)
|
||||
* Baud rate = Fsclk = Fssp / (2 * (SCR + 1)) (2)
|
||||
*
|
||||
* DDS_CLK_RATE either 2^n or 2^n / 5.
|
||||
* SCR is in range 0 .. 255
|
||||
*
|
||||
* Divisor = 5^i * 2^j * 2 * k
|
||||
* i = [0, 1] i = 1 iff j = 0 or j > 3
|
||||
* j = [0, 23] j = 0 iff i = 1
|
||||
* k = [1, 256]
|
||||
* Special case: j = 0, i = 1: Divisor = 2 / 5
|
||||
*
|
||||
* Accordingly to the specification the recommended values for DDS_CLK_RATE
|
||||
* are:
|
||||
* Case 1: 2^n, n = [0, 23]
|
||||
* Case 2: 2^24 * 2 / 5 (0x666666)
|
||||
* Case 3: less than or equal to 2^24 / 5 / 16 (0x33333)
|
||||
*
|
||||
* In all cases the lowest possible value is better.
|
||||
*
|
||||
* The function calculates parameters for all cases and chooses the one closest
|
||||
* to the asked baud rate.
|
||||
*/
|
||||
static u32 quark_x1000_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div)
|
||||
static unsigned int quark_x1000_get_clk_div(int rate, u32 *dds)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long xtal = 200000000;
|
||||
unsigned long fref = xtal / 2; /* mandatory division by 2,
|
||||
see (2) */
|
||||
/* case 3 */
|
||||
unsigned long fref1 = fref / 2; /* case 1 */
|
||||
unsigned long fref2 = fref * 2 / 5; /* case 2 */
|
||||
unsigned long scale;
|
||||
unsigned long q, q1, q2;
|
||||
long r, r1, r2;
|
||||
u32 mul;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(quark_spi_rate_table); i++) {
|
||||
if (rate >= quark_spi_rate_table[i].bitrate) {
|
||||
*dds = quark_spi_rate_table[i].dds_clk_rate;
|
||||
*clk_div = quark_spi_rate_table[i].clk_div;
|
||||
return quark_spi_rate_table[i].bitrate;
|
||||
/* Case 1 */
|
||||
|
||||
/* Set initial value for DDS_CLK_RATE */
|
||||
mul = (1 << 24) >> 1;
|
||||
|
||||
/* Calculate initial quot */
|
||||
q1 = DIV_ROUND_CLOSEST(fref1, rate);
|
||||
|
||||
/* Scale q1 if it's too big */
|
||||
if (q1 > 256) {
|
||||
/* Scale q1 to range [1, 512] */
|
||||
scale = fls_long(q1 - 1);
|
||||
if (scale > 9) {
|
||||
q1 >>= scale - 9;
|
||||
mul >>= scale - 9;
|
||||
}
|
||||
|
||||
/* Round the result if we have a remainder */
|
||||
q1 += q1 & 1;
|
||||
}
|
||||
|
||||
/* Decrease DDS_CLK_RATE as much as we can without loss in precision */
|
||||
scale = __ffs(q1);
|
||||
q1 >>= scale;
|
||||
mul >>= scale;
|
||||
|
||||
/* Get the remainder */
|
||||
r1 = abs(fref1 / (1 << (24 - fls_long(mul))) / q1 - rate);
|
||||
|
||||
/* Case 2 */
|
||||
|
||||
q2 = DIV_ROUND_CLOSEST(fref2, rate);
|
||||
r2 = abs(fref2 / q2 - rate);
|
||||
|
||||
/*
|
||||
* Choose the best between two: less remainder we have the better. We
|
||||
* can't go case 2 if q2 is greater than 256 since SCR register can
|
||||
* hold only values 0 .. 255.
|
||||
*/
|
||||
if (r2 >= r1 || q2 > 256) {
|
||||
/* case 1 is better */
|
||||
r = r1;
|
||||
q = q1;
|
||||
} else {
|
||||
/* case 2 is better */
|
||||
r = r2;
|
||||
q = q2;
|
||||
mul = (1 << 24) * 2 / 5;
|
||||
}
|
||||
|
||||
/* Check case 3 only If the divisor is big enough */
|
||||
if (fref / rate >= 80) {
|
||||
u64 fssp;
|
||||
u32 m;
|
||||
|
||||
/* Calculate initial quot */
|
||||
q1 = DIV_ROUND_CLOSEST(fref, rate);
|
||||
m = (1 << 24) / q1;
|
||||
|
||||
/* Get the remainder */
|
||||
fssp = (u64)fref * m;
|
||||
do_div(fssp, 1 << 24);
|
||||
r1 = abs(fssp - rate);
|
||||
|
||||
/* Choose this one if it suits better */
|
||||
if (r1 < r) {
|
||||
/* case 3 is better */
|
||||
q = 1;
|
||||
mul = m;
|
||||
}
|
||||
}
|
||||
|
||||
*dds = quark_spi_rate_table[i-1].dds_clk_rate;
|
||||
*clk_div = quark_spi_rate_table[i-1].clk_div;
|
||||
|
||||
return quark_spi_rate_table[i-1].bitrate;
|
||||
*dds = mul;
|
||||
return q - 1;
|
||||
}
|
||||
|
||||
static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
|
||||
@@ -730,23 +778,25 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
|
||||
rate = min_t(int, ssp_clk, rate);
|
||||
|
||||
if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
|
||||
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
|
||||
return (ssp_clk / (2 * rate) - 1) & 0xff;
|
||||
else
|
||||
return ((ssp_clk / rate - 1) & 0xfff) << 8;
|
||||
return (ssp_clk / rate - 1) & 0xfff;
|
||||
}
|
||||
|
||||
static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
|
||||
struct chip_data *chip, int rate)
|
||||
{
|
||||
u32 clk_div;
|
||||
unsigned int clk_div;
|
||||
|
||||
switch (drv_data->ssp_type) {
|
||||
case QUARK_X1000_SSP:
|
||||
quark_x1000_set_clk_regvals(rate, &chip->dds_rate, &clk_div);
|
||||
return clk_div << 8;
|
||||
clk_div = quark_x1000_get_clk_div(rate, &chip->dds_rate);
|
||||
break;
|
||||
default:
|
||||
return ssp_get_clk_div(drv_data, rate);
|
||||
clk_div = ssp_get_clk_div(drv_data, rate);
|
||||
break;
|
||||
}
|
||||
return clk_div << 8;
|
||||
}
|
||||
|
||||
static void pump_transfers(unsigned long data)
|
||||
|
||||
+309
-36
@@ -22,6 +22,8 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/dmaengine.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#define QUP_CONFIG 0x0000
|
||||
#define QUP_STATE 0x0004
|
||||
@@ -116,6 +118,8 @@
|
||||
|
||||
#define SPI_NUM_CHIPSELECTS 4
|
||||
|
||||
#define SPI_MAX_DMA_XFER (SZ_64K - 64)
|
||||
|
||||
/* high speed mode is when bus rate is greater then 26MHz */
|
||||
#define SPI_HS_MIN_RATE 26000000
|
||||
#define SPI_MAX_RATE 50000000
|
||||
@@ -140,9 +144,14 @@ struct spi_qup {
|
||||
struct completion done;
|
||||
int error;
|
||||
int w_size; /* bytes per SPI word */
|
||||
int n_words;
|
||||
int tx_bytes;
|
||||
int rx_bytes;
|
||||
int qup_v1;
|
||||
|
||||
int use_dma;
|
||||
struct dma_slave_config rx_conf;
|
||||
struct dma_slave_config tx_conf;
|
||||
};
|
||||
|
||||
|
||||
@@ -198,7 +207,6 @@ static int spi_qup_set_state(struct spi_qup *controller, u32 state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void spi_qup_fifo_read(struct spi_qup *controller,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
@@ -266,6 +274,107 @@ static void spi_qup_fifo_write(struct spi_qup *controller,
|
||||
}
|
||||
}
|
||||
|
||||
static void spi_qup_dma_done(void *data)
|
||||
{
|
||||
struct spi_qup *qup = data;
|
||||
|
||||
complete(&qup->done);
|
||||
}
|
||||
|
||||
static int spi_qup_prep_sg(struct spi_master *master, struct spi_transfer *xfer,
|
||||
enum dma_transfer_direction dir,
|
||||
dma_async_tx_callback callback)
|
||||
{
|
||||
struct spi_qup *qup = spi_master_get_devdata(master);
|
||||
unsigned long flags = DMA_PREP_INTERRUPT | DMA_PREP_FENCE;
|
||||
struct dma_async_tx_descriptor *desc;
|
||||
struct scatterlist *sgl;
|
||||
struct dma_chan *chan;
|
||||
dma_cookie_t cookie;
|
||||
unsigned int nents;
|
||||
|
||||
if (dir == DMA_MEM_TO_DEV) {
|
||||
chan = master->dma_tx;
|
||||
nents = xfer->tx_sg.nents;
|
||||
sgl = xfer->tx_sg.sgl;
|
||||
} else {
|
||||
chan = master->dma_rx;
|
||||
nents = xfer->rx_sg.nents;
|
||||
sgl = xfer->rx_sg.sgl;
|
||||
}
|
||||
|
||||
desc = dmaengine_prep_slave_sg(chan, sgl, nents, dir, flags);
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
desc->callback = callback;
|
||||
desc->callback_param = qup;
|
||||
|
||||
cookie = dmaengine_submit(desc);
|
||||
|
||||
return dma_submit_error(cookie);
|
||||
}
|
||||
|
||||
static void spi_qup_dma_terminate(struct spi_master *master,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
if (xfer->tx_buf)
|
||||
dmaengine_terminate_all(master->dma_tx);
|
||||
if (xfer->rx_buf)
|
||||
dmaengine_terminate_all(master->dma_rx);
|
||||
}
|
||||
|
||||
static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer)
|
||||
{
|
||||
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
|
||||
int ret;
|
||||
|
||||
if (xfer->rx_buf)
|
||||
rx_done = spi_qup_dma_done;
|
||||
else if (xfer->tx_buf)
|
||||
tx_done = spi_qup_dma_done;
|
||||
|
||||
if (xfer->rx_buf) {
|
||||
ret = spi_qup_prep_sg(master, xfer, DMA_DEV_TO_MEM, rx_done);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dma_async_issue_pending(master->dma_rx);
|
||||
}
|
||||
|
||||
if (xfer->tx_buf) {
|
||||
ret = spi_qup_prep_sg(master, xfer, DMA_MEM_TO_DEV, tx_done);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dma_async_issue_pending(master->dma_tx);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_qup *qup = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
|
||||
if (ret) {
|
||||
dev_warn(qup->dev, "cannot set RUN state\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
|
||||
if (ret) {
|
||||
dev_warn(qup->dev, "cannot set PAUSE state\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi_qup_fifo_write(qup, xfer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct spi_qup *controller = dev_id;
|
||||
@@ -315,11 +424,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
|
||||
error = -EIO;
|
||||
}
|
||||
|
||||
if (opflags & QUP_OP_IN_SERVICE_FLAG)
|
||||
spi_qup_fifo_read(controller, xfer);
|
||||
if (!controller->use_dma) {
|
||||
if (opflags & QUP_OP_IN_SERVICE_FLAG)
|
||||
spi_qup_fifo_read(controller, xfer);
|
||||
|
||||
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
|
||||
spi_qup_fifo_write(controller, xfer);
|
||||
if (opflags & QUP_OP_OUT_SERVICE_FLAG)
|
||||
spi_qup_fifo_write(controller, xfer);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&controller->lock, flags);
|
||||
controller->error = error;
|
||||
@@ -332,13 +443,35 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static u32
|
||||
spi_qup_get_mode(struct spi_master *master, struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_qup *qup = spi_master_get_devdata(master);
|
||||
u32 mode;
|
||||
|
||||
qup->w_size = 4;
|
||||
|
||||
if (xfer->bits_per_word <= 8)
|
||||
qup->w_size = 1;
|
||||
else if (xfer->bits_per_word <= 16)
|
||||
qup->w_size = 2;
|
||||
|
||||
qup->n_words = xfer->len / qup->w_size;
|
||||
|
||||
if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
|
||||
mode = QUP_IO_M_MODE_FIFO;
|
||||
else
|
||||
mode = QUP_IO_M_MODE_BLOCK;
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
/* set clock freq ... bits per word */
|
||||
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_qup *controller = spi_master_get_devdata(spi->master);
|
||||
u32 config, iomode, mode, control;
|
||||
int ret, n_words, w_size;
|
||||
int ret, n_words;
|
||||
|
||||
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
|
||||
dev_err(controller->dev, "too big size for loopback %d > %d\n",
|
||||
@@ -358,35 +491,54 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
w_size = 4;
|
||||
if (xfer->bits_per_word <= 8)
|
||||
w_size = 1;
|
||||
else if (xfer->bits_per_word <= 16)
|
||||
w_size = 2;
|
||||
mode = spi_qup_get_mode(spi->master, xfer);
|
||||
n_words = controller->n_words;
|
||||
|
||||
n_words = xfer->len / w_size;
|
||||
controller->w_size = w_size;
|
||||
|
||||
if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
|
||||
mode = QUP_IO_M_MODE_FIFO;
|
||||
if (mode == QUP_IO_M_MODE_FIFO) {
|
||||
writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
|
||||
writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
|
||||
/* must be zero for FIFO */
|
||||
writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
|
||||
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
|
||||
} else {
|
||||
mode = QUP_IO_M_MODE_BLOCK;
|
||||
} else if (!controller->use_dma) {
|
||||
writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
|
||||
writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
|
||||
/* must be zero for BLOCK and BAM */
|
||||
writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
|
||||
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
|
||||
} else {
|
||||
mode = QUP_IO_M_MODE_BAM;
|
||||
writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
|
||||
writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
|
||||
|
||||
if (!controller->qup_v1) {
|
||||
void __iomem *input_cnt;
|
||||
|
||||
input_cnt = controller->base + QUP_MX_INPUT_CNT;
|
||||
/*
|
||||
* for DMA transfers, both QUP_MX_INPUT_CNT and
|
||||
* QUP_MX_OUTPUT_CNT must be zero to all cases but one.
|
||||
* That case is a non-balanced transfer when there is
|
||||
* only a rx_buf.
|
||||
*/
|
||||
if (xfer->tx_buf)
|
||||
writel_relaxed(0, input_cnt);
|
||||
else
|
||||
writel_relaxed(n_words, input_cnt);
|
||||
|
||||
writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
|
||||
}
|
||||
}
|
||||
|
||||
iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
|
||||
/* Set input and output transfer mode */
|
||||
iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
|
||||
iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
|
||||
|
||||
if (!controller->use_dma)
|
||||
iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
|
||||
else
|
||||
iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
|
||||
|
||||
iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
|
||||
iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
|
||||
|
||||
@@ -428,11 +580,31 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
|
||||
config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
|
||||
config |= xfer->bits_per_word - 1;
|
||||
config |= QUP_CONFIG_SPI_MODE;
|
||||
|
||||
if (controller->use_dma) {
|
||||
if (!xfer->tx_buf)
|
||||
config |= QUP_CONFIG_NO_OUTPUT;
|
||||
if (!xfer->rx_buf)
|
||||
config |= QUP_CONFIG_NO_INPUT;
|
||||
}
|
||||
|
||||
writel_relaxed(config, controller->base + QUP_CONFIG);
|
||||
|
||||
/* only write to OPERATIONAL_MASK when register is present */
|
||||
if (!controller->qup_v1)
|
||||
writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK);
|
||||
if (!controller->qup_v1) {
|
||||
u32 mask = 0;
|
||||
|
||||
/*
|
||||
* mask INPUT and OUTPUT service flags to prevent IRQs on FIFO
|
||||
* status change in BAM mode
|
||||
*/
|
||||
|
||||
if (mode == QUP_IO_M_MODE_BAM)
|
||||
mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
|
||||
|
||||
writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -461,17 +633,13 @@ static int spi_qup_transfer_one(struct spi_master *master,
|
||||
controller->tx_bytes = 0;
|
||||
spin_unlock_irqrestore(&controller->lock, flags);
|
||||
|
||||
if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
|
||||
dev_warn(controller->dev, "cannot set RUN state\n");
|
||||
goto exit;
|
||||
}
|
||||
if (controller->use_dma)
|
||||
ret = spi_qup_do_dma(master, xfer);
|
||||
else
|
||||
ret = spi_qup_do_pio(master, xfer);
|
||||
|
||||
if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
|
||||
dev_warn(controller->dev, "cannot set PAUSE state\n");
|
||||
if (ret)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spi_qup_fifo_write(controller, xfer);
|
||||
|
||||
if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
|
||||
dev_warn(controller->dev, "cannot set EXECUTE state\n");
|
||||
@@ -480,6 +648,7 @@ static int spi_qup_transfer_one(struct spi_master *master,
|
||||
|
||||
if (!wait_for_completion_timeout(&controller->done, timeout))
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
exit:
|
||||
spi_qup_set_state(controller, QUP_STATE_RESET);
|
||||
spin_lock_irqsave(&controller->lock, flags);
|
||||
@@ -487,6 +656,97 @@ exit:
|
||||
if (!ret)
|
||||
ret = controller->error;
|
||||
spin_unlock_irqrestore(&controller->lock, flags);
|
||||
|
||||
if (ret && controller->use_dma)
|
||||
spi_qup_dma_terminate(master, xfer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool spi_qup_can_dma(struct spi_master *master, struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct spi_qup *qup = spi_master_get_devdata(master);
|
||||
size_t dma_align = dma_get_cache_alignment();
|
||||
u32 mode;
|
||||
|
||||
qup->use_dma = 0;
|
||||
|
||||
if (xfer->rx_buf && (xfer->len % qup->in_blk_sz ||
|
||||
IS_ERR_OR_NULL(master->dma_rx) ||
|
||||
!IS_ALIGNED((size_t)xfer->rx_buf, dma_align)))
|
||||
return false;
|
||||
|
||||
if (xfer->tx_buf && (xfer->len % qup->out_blk_sz ||
|
||||
IS_ERR_OR_NULL(master->dma_tx) ||
|
||||
!IS_ALIGNED((size_t)xfer->tx_buf, dma_align)))
|
||||
return false;
|
||||
|
||||
mode = spi_qup_get_mode(master, xfer);
|
||||
if (mode == QUP_IO_M_MODE_FIFO)
|
||||
return false;
|
||||
|
||||
qup->use_dma = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void spi_qup_release_dma(struct spi_master *master)
|
||||
{
|
||||
if (!IS_ERR_OR_NULL(master->dma_rx))
|
||||
dma_release_channel(master->dma_rx);
|
||||
if (!IS_ERR_OR_NULL(master->dma_tx))
|
||||
dma_release_channel(master->dma_tx);
|
||||
}
|
||||
|
||||
static int spi_qup_init_dma(struct spi_master *master, resource_size_t base)
|
||||
{
|
||||
struct spi_qup *spi = spi_master_get_devdata(master);
|
||||
struct dma_slave_config *rx_conf = &spi->rx_conf,
|
||||
*tx_conf = &spi->tx_conf;
|
||||
struct device *dev = spi->dev;
|
||||
int ret;
|
||||
|
||||
/* allocate dma resources, if available */
|
||||
master->dma_rx = dma_request_slave_channel_reason(dev, "rx");
|
||||
if (IS_ERR(master->dma_rx))
|
||||
return PTR_ERR(master->dma_rx);
|
||||
|
||||
master->dma_tx = dma_request_slave_channel_reason(dev, "tx");
|
||||
if (IS_ERR(master->dma_tx)) {
|
||||
ret = PTR_ERR(master->dma_tx);
|
||||
goto err_tx;
|
||||
}
|
||||
|
||||
/* set DMA parameters */
|
||||
rx_conf->direction = DMA_DEV_TO_MEM;
|
||||
rx_conf->device_fc = 1;
|
||||
rx_conf->src_addr = base + QUP_INPUT_FIFO;
|
||||
rx_conf->src_maxburst = spi->in_blk_sz;
|
||||
|
||||
tx_conf->direction = DMA_MEM_TO_DEV;
|
||||
tx_conf->device_fc = 1;
|
||||
tx_conf->dst_addr = base + QUP_OUTPUT_FIFO;
|
||||
tx_conf->dst_maxburst = spi->out_blk_sz;
|
||||
|
||||
ret = dmaengine_slave_config(master->dma_rx, rx_conf);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to configure RX channel\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = dmaengine_slave_config(master->dma_tx, tx_conf);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to configure TX channel\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
dma_release_channel(master->dma_tx);
|
||||
err_tx:
|
||||
dma_release_channel(master->dma_rx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -498,7 +758,7 @@ static int spi_qup_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
struct device *dev;
|
||||
void __iomem *base;
|
||||
u32 max_freq, iomode;
|
||||
u32 max_freq, iomode, num_cs;
|
||||
int ret, irq, size;
|
||||
|
||||
dev = &pdev->dev;
|
||||
@@ -550,10 +810,11 @@ static int spi_qup_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* use num-cs unless not present or out of range */
|
||||
if (of_property_read_u16(dev->of_node, "num-cs",
|
||||
&master->num_chipselect) ||
|
||||
(master->num_chipselect > SPI_NUM_CHIPSELECTS))
|
||||
if (of_property_read_u32(dev->of_node, "num-cs", &num_cs) ||
|
||||
num_cs > SPI_NUM_CHIPSELECTS)
|
||||
master->num_chipselect = SPI_NUM_CHIPSELECTS;
|
||||
else
|
||||
master->num_chipselect = num_cs;
|
||||
|
||||
master->bus_num = pdev->id;
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
|
||||
@@ -562,6 +823,8 @@ static int spi_qup_probe(struct platform_device *pdev)
|
||||
master->transfer_one = spi_qup_transfer_one;
|
||||
master->dev.of_node = pdev->dev.of_node;
|
||||
master->auto_runtime_pm = true;
|
||||
master->dma_alignment = dma_get_cache_alignment();
|
||||
master->max_dma_len = SPI_MAX_DMA_XFER;
|
||||
|
||||
platform_set_drvdata(pdev, master);
|
||||
|
||||
@@ -573,6 +836,12 @@ static int spi_qup_probe(struct platform_device *pdev)
|
||||
controller->cclk = cclk;
|
||||
controller->irq = irq;
|
||||
|
||||
ret = spi_qup_init_dma(master, res->start);
|
||||
if (ret == -EPROBE_DEFER)
|
||||
goto error;
|
||||
else if (!ret)
|
||||
master->can_dma = spi_qup_can_dma;
|
||||
|
||||
/* set v1 flag if device is version 1 */
|
||||
if (of_device_is_compatible(dev->of_node, "qcom,spi-qup-v1.1.1"))
|
||||
controller->qup_v1 = 1;
|
||||
@@ -609,7 +878,7 @@ static int spi_qup_probe(struct platform_device *pdev)
|
||||
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot set RESET state\n");
|
||||
goto error;
|
||||
goto error_dma;
|
||||
}
|
||||
|
||||
writel_relaxed(0, base + QUP_OPERATIONAL);
|
||||
@@ -633,7 +902,7 @@ static int spi_qup_probe(struct platform_device *pdev)
|
||||
ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
|
||||
IRQF_TRIGGER_HIGH, pdev->name, controller);
|
||||
if (ret)
|
||||
goto error;
|
||||
goto error_dma;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
@@ -648,6 +917,8 @@ static int spi_qup_probe(struct platform_device *pdev)
|
||||
|
||||
disable_pm:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
error_dma:
|
||||
spi_qup_release_dma(master);
|
||||
error:
|
||||
clk_disable_unprepare(cclk);
|
||||
clk_disable_unprepare(iclk);
|
||||
@@ -739,6 +1010,8 @@ static int spi_qup_remove(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
spi_qup_release_dma(master);
|
||||
|
||||
clk_disable_unprepare(controller->cclk);
|
||||
clk_disable_unprepare(controller->iclk);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user