Merge remote-tracking branches 'spi/topic/qup', 'spi/topic/rockchip', 'spi/topic/rspi', 'spi/topic/s3c64xx' and 'spi/topic/sc18is602' into spi-next
This commit is contained in:
commit
165f2288e1
7 changed files with 469 additions and 47 deletions
|
@ -33,6 +33,11 @@ Optional properties:
|
|||
nodes. If unspecified, a single SPI device without a chip
|
||||
select can be used.
|
||||
|
||||
- dmas: Two DMA channel specifiers following the convention outlined
|
||||
in bindings/dma/dma.txt
|
||||
- dma-names: Names for the dma channels, if present. There must be at
|
||||
least one channel named "tx" for transmit and named "rx" for
|
||||
receive.
|
||||
|
||||
SPI slave nodes must be children of the SPI master node and can contain
|
||||
properties described in Documentation/devicetree/bindings/spi/spi-bus.txt
|
||||
|
@ -51,6 +56,9 @@ Example:
|
|||
clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
|
||||
clock-names = "core", "iface";
|
||||
|
||||
dmas = <&blsp1_bam 13>, <&blsp1_bam 12>;
|
||||
dma-names = "rx", "tx";
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&spi8_default>;
|
||||
|
||||
|
|
|
@ -24,6 +24,9 @@ Optional Properties:
|
|||
- dmas: DMA specifiers for tx and rx dma. See the DMA client binding,
|
||||
Documentation/devicetree/bindings/dma/dma.txt
|
||||
- dma-names: DMA request names should include "tx" and "rx" if present.
|
||||
- rx-sample-delay-ns: nanoseconds to delay after the SCLK edge before sampling
|
||||
Rx data (may need to be fine tuned for high capacitance lines).
|
||||
No delay (0) by default.
|
||||
|
||||
|
||||
Example:
|
||||
|
@ -33,6 +36,7 @@ Example:
|
|||
reg = <0xff110000 0x1000>;
|
||||
dmas = <&pdma1 11>, <&pdma1 12>;
|
||||
dma-names = "tx", "rx";
|
||||
rx-sample-delay-ns = <10>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
|
|
@ -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 @@ static int spi_qup_transfer_one(struct spi_master *master,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -563,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);
|
||||
|
||||
|
@ -574,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;
|
||||
|
@ -610,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);
|
||||
|
@ -634,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);
|
||||
|
@ -649,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);
|
||||
|
@ -740,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);
|
||||
|
||||
|
|
|
@ -179,6 +179,7 @@ struct rockchip_spi {
|
|||
u8 tmode;
|
||||
u8 bpw;
|
||||
u8 n_bytes;
|
||||
u8 rsd_nsecs;
|
||||
unsigned len;
|
||||
u32 speed;
|
||||
|
||||
|
@ -302,8 +303,8 @@ static int rockchip_spi_prepare_message(struct spi_master *master,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_spi_unprepare_message(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
static void rockchip_spi_handle_err(struct spi_master *master,
|
||||
struct spi_message *msg)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct rockchip_spi *rs = spi_master_get_devdata(master);
|
||||
|
@ -313,8 +314,8 @@ static int rockchip_spi_unprepare_message(struct spi_master *master,
|
|||
/*
|
||||
* 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.
|
||||
* handle_err() was called by core if transfer failed.
|
||||
* Maybe it is reasonable for error handling here.
|
||||
*/
|
||||
if (rs->use_dma) {
|
||||
if (rs->state & RXBUSY) {
|
||||
|
@ -327,6 +328,12 @@ static int rockchip_spi_unprepare_message(struct spi_master *master,
|
|||
}
|
||||
|
||||
spin_unlock_irqrestore(&rs->lock, flags);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -493,6 +500,7 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
|
|||
{
|
||||
u32 div = 0;
|
||||
u32 dmacr = 0;
|
||||
int rsd = 0;
|
||||
|
||||
u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
|
||||
| (CR0_SSD_ONE << CR0_SSD_OFFSET);
|
||||
|
@ -522,6 +530,20 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
|
|||
div = DIV_ROUND_UP(rs->max_freq, rs->speed);
|
||||
div = (div + 1) & 0xfffe;
|
||||
|
||||
/* Rx sample delay is expressed in parent clock cycles (max 3) */
|
||||
rsd = DIV_ROUND_CLOSEST(rs->rsd_nsecs * (rs->max_freq >> 8),
|
||||
1000000000 >> 8);
|
||||
if (!rsd && rs->rsd_nsecs) {
|
||||
pr_warn_once("rockchip-spi: %u Hz are too slow to express %u ns delay\n",
|
||||
rs->max_freq, rs->rsd_nsecs);
|
||||
} else if (rsd > 3) {
|
||||
rsd = 3;
|
||||
pr_warn_once("rockchip-spi: %u Hz are too fast to express %u ns delay, clamping at %u ns\n",
|
||||
rs->max_freq, rs->rsd_nsecs,
|
||||
rsd * 1000000000U / rs->max_freq);
|
||||
}
|
||||
cr0 |= rsd << CR0_RSD_OFFSET;
|
||||
|
||||
writel_relaxed(cr0, rs->regs + ROCKCHIP_SPI_CTRLR0);
|
||||
|
||||
writel_relaxed(rs->len - 1, rs->regs + ROCKCHIP_SPI_CTRLR1);
|
||||
|
@ -614,6 +636,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
|
|||
struct rockchip_spi *rs;
|
||||
struct spi_master *master;
|
||||
struct resource *mem;
|
||||
u32 rsd_nsecs;
|
||||
|
||||
master = spi_alloc_master(&pdev->dev, sizeof(struct rockchip_spi));
|
||||
if (!master)
|
||||
|
@ -665,6 +688,10 @@ static int rockchip_spi_probe(struct platform_device *pdev)
|
|||
rs->dev = &pdev->dev;
|
||||
rs->max_freq = clk_get_rate(rs->spiclk);
|
||||
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "rx-sample-delay-ns",
|
||||
&rsd_nsecs))
|
||||
rs->rsd_nsecs = rsd_nsecs;
|
||||
|
||||
rs->fifo_len = get_fifo_len(rs);
|
||||
if (!rs->fifo_len) {
|
||||
dev_err(&pdev->dev, "Failed to get fifo length\n");
|
||||
|
@ -688,6 +715,7 @@ static int rockchip_spi_probe(struct platform_device *pdev)
|
|||
master->prepare_message = rockchip_spi_prepare_message;
|
||||
master->unprepare_message = rockchip_spi_unprepare_message;
|
||||
master->transfer_one = rockchip_spi_transfer_one;
|
||||
master->handle_err = rockchip_spi_handle_err;
|
||||
|
||||
rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx");
|
||||
if (!rs->dma_tx.ch)
|
||||
|
|
|
@ -177,6 +177,13 @@
|
|||
#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset */
|
||||
#define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */
|
||||
#define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */
|
||||
/* QSPI on R-Car Gen2 */
|
||||
#define SPBFCR_TXTRG_1B 0x00 /* 31 bytes (1 byte available) */
|
||||
#define SPBFCR_TXTRG_32B 0x30 /* 0 byte (32 bytes available) */
|
||||
#define SPBFCR_RXTRG_1B 0x00 /* 1 byte (31 bytes available) */
|
||||
#define SPBFCR_RXTRG_32B 0x07 /* 32 bytes (0 byte available) */
|
||||
|
||||
#define QSPI_BUFFER_SIZE 32u
|
||||
|
||||
struct rspi_data {
|
||||
void __iomem *addr;
|
||||
|
@ -366,6 +373,52 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void qspi_update(const struct rspi_data *rspi, u8 mask, u8 val, u8 reg)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
data = rspi_read8(rspi, reg);
|
||||
data &= ~mask;
|
||||
data |= (val & mask);
|
||||
rspi_write8(rspi, data, reg);
|
||||
}
|
||||
|
||||
static int qspi_set_send_trigger(struct rspi_data *rspi, unsigned int len)
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
n = min(len, QSPI_BUFFER_SIZE);
|
||||
|
||||
if (len >= QSPI_BUFFER_SIZE) {
|
||||
/* sets triggering number to 32 bytes */
|
||||
qspi_update(rspi, SPBFCR_TXTRG_MASK,
|
||||
SPBFCR_TXTRG_32B, QSPI_SPBFCR);
|
||||
} else {
|
||||
/* sets triggering number to 1 byte */
|
||||
qspi_update(rspi, SPBFCR_TXTRG_MASK,
|
||||
SPBFCR_TXTRG_1B, QSPI_SPBFCR);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
static void qspi_set_receive_trigger(struct rspi_data *rspi, unsigned int len)
|
||||
{
|
||||
unsigned int n;
|
||||
|
||||
n = min(len, QSPI_BUFFER_SIZE);
|
||||
|
||||
if (len >= QSPI_BUFFER_SIZE) {
|
||||
/* sets triggering number to 32 bytes */
|
||||
qspi_update(rspi, SPBFCR_RXTRG_MASK,
|
||||
SPBFCR_RXTRG_32B, QSPI_SPBFCR);
|
||||
} else {
|
||||
/* sets triggering number to 1 byte */
|
||||
qspi_update(rspi, SPBFCR_RXTRG_MASK,
|
||||
SPBFCR_RXTRG_1B, QSPI_SPBFCR);
|
||||
}
|
||||
}
|
||||
|
||||
#define set_config_register(spi, n) spi->ops->set_config_register(spi, n)
|
||||
|
||||
static void rspi_enable_irq(const struct rspi_data *rspi, u8 enable)
|
||||
|
@ -609,18 +662,28 @@ static bool rspi_can_dma(struct spi_master *master, struct spi_device *spi,
|
|||
return __rspi_can_dma(rspi, xfer);
|
||||
}
|
||||
|
||||
static int rspi_dma_check_then_transfer(struct rspi_data *rspi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) {
|
||||
/* rx_buf can be NULL on RSPI on SH in TX-only Mode */
|
||||
int ret = rspi_dma_transfer(rspi, &xfer->tx_sg,
|
||||
xfer->rx_buf ? &xfer->rx_sg : NULL);
|
||||
if (ret != -EAGAIN)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static int rspi_common_transfer(struct rspi_data *rspi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (rspi->master->can_dma && __rspi_can_dma(rspi, xfer)) {
|
||||
/* rx_buf can be NULL on RSPI on SH in TX-only Mode */
|
||||
ret = rspi_dma_transfer(rspi, &xfer->tx_sg,
|
||||
xfer->rx_buf ? &xfer->rx_sg : NULL);
|
||||
if (ret != -EAGAIN)
|
||||
return ret;
|
||||
}
|
||||
ret = rspi_dma_check_then_transfer(rspi, xfer);
|
||||
if (ret != -EAGAIN)
|
||||
return ret;
|
||||
|
||||
ret = rspi_pio_transfer(rspi, xfer->tx_buf, xfer->rx_buf, xfer->len);
|
||||
if (ret < 0)
|
||||
|
@ -661,12 +724,59 @@ static int rspi_rz_transfer_one(struct spi_master *master,
|
|||
return rspi_common_transfer(rspi, xfer);
|
||||
}
|
||||
|
||||
static int qspi_trigger_transfer_out_int(struct rspi_data *rspi, const u8 *tx,
|
||||
u8 *rx, unsigned int len)
|
||||
{
|
||||
int i, n, ret;
|
||||
int error;
|
||||
|
||||
while (len > 0) {
|
||||
n = qspi_set_send_trigger(rspi, len);
|
||||
qspi_set_receive_trigger(rspi, len);
|
||||
if (n == QSPI_BUFFER_SIZE) {
|
||||
error = rspi_wait_for_tx_empty(rspi);
|
||||
if (error < 0) {
|
||||
dev_err(&rspi->master->dev, "transmit timeout\n");
|
||||
return error;
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
rspi_write_data(rspi, *tx++);
|
||||
|
||||
error = rspi_wait_for_rx_full(rspi);
|
||||
if (error < 0) {
|
||||
dev_err(&rspi->master->dev, "receive timeout\n");
|
||||
return error;
|
||||
}
|
||||
for (i = 0; i < n; i++)
|
||||
*rx++ = rspi_read_data(rspi);
|
||||
} else {
|
||||
ret = rspi_pio_transfer(rspi, tx, rx, n);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
len -= n;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qspi_transfer_out_in(struct rspi_data *rspi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
int ret;
|
||||
|
||||
qspi_receive_init(rspi);
|
||||
|
||||
return rspi_common_transfer(rspi, xfer);
|
||||
ret = rspi_dma_check_then_transfer(rspi, xfer);
|
||||
if (ret != -EAGAIN)
|
||||
return ret;
|
||||
|
||||
ret = qspi_trigger_transfer_out_int(rspi, xfer->tx_buf,
|
||||
xfer->rx_buf, xfer->len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer)
|
||||
|
|
|
@ -324,7 +324,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
|
|||
|
||||
/* Acquire DMA channels */
|
||||
sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter,
|
||||
(void *)sdd->rx_dma.dmach, dev, "rx");
|
||||
(void *)(long)sdd->rx_dma.dmach, dev, "rx");
|
||||
if (!sdd->rx_dma.ch) {
|
||||
dev_err(dev, "Failed to get RX DMA channel\n");
|
||||
ret = -EBUSY;
|
||||
|
@ -333,7 +333,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
|
|||
spi->dma_rx = sdd->rx_dma.ch;
|
||||
|
||||
sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter,
|
||||
(void *)sdd->tx_dma.dmach, dev, "tx");
|
||||
(void *)(long)sdd->tx_dma.dmach, dev, "tx");
|
||||
if (!sdd->tx_dma.ch) {
|
||||
dev_err(dev, "Failed to get TX DMA channel\n");
|
||||
ret = -EBUSY;
|
||||
|
|
|
@ -286,7 +286,7 @@ static int sc18is602_probe(struct i2c_client *client,
|
|||
hw->freq = SC18IS602_CLOCK;
|
||||
break;
|
||||
}
|
||||
master->bus_num = client->adapter->nr;
|
||||
master->bus_num = np ? -1 : client->adapter->nr;
|
||||
master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||
master->setup = sc18is602_setup;
|
||||
|
|
Loading…
Reference in a new issue