Merge branch 'spi-5.4' into spi-next
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
@@ -16,6 +17,7 @@
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#define SSI_TIMEOUT_MS 2000
|
||||
#define SSI_POLL_TIMEOUT_US 200
|
||||
#define SSI_MAX_CLK_DIVIDER 254
|
||||
#define SSI_MIN_CLK_DIVIDER 4
|
||||
|
||||
@@ -227,8 +229,7 @@ static void uniphier_spi_setup_transfer(struct spi_device *spi,
|
||||
priv->speed_hz = t->speed_hz;
|
||||
}
|
||||
|
||||
if (!priv->is_save_param)
|
||||
priv->is_save_param = true;
|
||||
priv->is_save_param = true;
|
||||
|
||||
/* reset FIFOs */
|
||||
val = SSI_FC_TXFFL | SSI_FC_RXFFL;
|
||||
@@ -291,21 +292,23 @@ static void uniphier_spi_recv(struct uniphier_spi_priv *priv)
|
||||
|
||||
static void uniphier_spi_fill_tx_fifo(struct uniphier_spi_priv *priv)
|
||||
{
|
||||
unsigned int tx_count;
|
||||
unsigned int fifo_threshold, fill_bytes;
|
||||
u32 val;
|
||||
|
||||
tx_count = DIV_ROUND_UP(priv->tx_bytes,
|
||||
fifo_threshold = DIV_ROUND_UP(priv->rx_bytes,
|
||||
bytes_per_word(priv->bits_per_word));
|
||||
tx_count = min(tx_count, SSI_FIFO_DEPTH);
|
||||
fifo_threshold = min(fifo_threshold, SSI_FIFO_DEPTH);
|
||||
|
||||
fill_bytes = fifo_threshold - (priv->rx_bytes - priv->tx_bytes);
|
||||
|
||||
/* set fifo threshold */
|
||||
val = readl(priv->base + SSI_FC);
|
||||
val &= ~(SSI_FC_TXFTH_MASK | SSI_FC_RXFTH_MASK);
|
||||
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, tx_count);
|
||||
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, tx_count);
|
||||
val |= FIELD_PREP(SSI_FC_TXFTH_MASK, fifo_threshold);
|
||||
val |= FIELD_PREP(SSI_FC_RXFTH_MASK, fifo_threshold);
|
||||
writel(val, priv->base + SSI_FC);
|
||||
|
||||
while (tx_count--)
|
||||
while (fill_bytes--)
|
||||
uniphier_spi_send(priv);
|
||||
}
|
||||
|
||||
@@ -324,20 +327,14 @@ static void uniphier_spi_set_cs(struct spi_device *spi, bool enable)
|
||||
writel(val, priv->base + SSI_FPS);
|
||||
}
|
||||
|
||||
static int uniphier_spi_transfer_one(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
static int uniphier_spi_transfer_one_irq(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
{
|
||||
struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
|
||||
struct device *dev = master->dev.parent;
|
||||
unsigned long time_left;
|
||||
|
||||
/* Terminate and return success for 0 byte length transfer */
|
||||
if (!t->len)
|
||||
return 0;
|
||||
|
||||
uniphier_spi_setup_transfer(spi, t);
|
||||
|
||||
reinit_completion(&priv->xfer_done);
|
||||
|
||||
uniphier_spi_fill_tx_fifo(priv);
|
||||
@@ -357,6 +354,59 @@ static int uniphier_spi_transfer_one(struct spi_master *master,
|
||||
return priv->error;
|
||||
}
|
||||
|
||||
static int uniphier_spi_transfer_one_poll(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
{
|
||||
struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
|
||||
int loop = SSI_POLL_TIMEOUT_US * 10;
|
||||
|
||||
while (priv->tx_bytes) {
|
||||
uniphier_spi_fill_tx_fifo(priv);
|
||||
|
||||
while ((priv->rx_bytes - priv->tx_bytes) > 0) {
|
||||
while (!(readl(priv->base + SSI_SR) & SSI_SR_RNE)
|
||||
&& loop--)
|
||||
ndelay(100);
|
||||
|
||||
if (loop == -1)
|
||||
goto irq_transfer;
|
||||
|
||||
uniphier_spi_recv(priv);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
irq_transfer:
|
||||
return uniphier_spi_transfer_one_irq(master, spi, t);
|
||||
}
|
||||
|
||||
static int uniphier_spi_transfer_one(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *t)
|
||||
{
|
||||
struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
|
||||
unsigned long threshold;
|
||||
|
||||
/* Terminate and return success for 0 byte length transfer */
|
||||
if (!t->len)
|
||||
return 0;
|
||||
|
||||
uniphier_spi_setup_transfer(spi, t);
|
||||
|
||||
/*
|
||||
* If the transfer operation will take longer than
|
||||
* SSI_POLL_TIMEOUT_US, it should use irq.
|
||||
*/
|
||||
threshold = DIV_ROUND_UP(SSI_POLL_TIMEOUT_US * priv->speed_hz,
|
||||
USEC_PER_SEC * BITS_PER_BYTE);
|
||||
if (t->len > threshold)
|
||||
return uniphier_spi_transfer_one_irq(master, spi, t);
|
||||
else
|
||||
return uniphier_spi_transfer_one_poll(master, spi, t);
|
||||
}
|
||||
|
||||
static int uniphier_spi_prepare_transfer_hardware(struct spi_master *master)
|
||||
{
|
||||
struct uniphier_spi_priv *priv = spi_master_get_devdata(master);
|
||||
@@ -420,7 +470,6 @@ static int uniphier_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier_spi_priv *priv;
|
||||
struct spi_master *master;
|
||||
struct resource *res;
|
||||
unsigned long clk_rate;
|
||||
int irq;
|
||||
int ret;
|
||||
@@ -435,8 +484,7 @@ static int uniphier_spi_probe(struct platform_device *pdev)
|
||||
priv->master = master;
|
||||
priv->is_save_param = false;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base)) {
|
||||
ret = PTR_ERR(priv->base);
|
||||
goto out_master_put;
|
||||
@@ -455,7 +503,6 @@ static int uniphier_spi_probe(struct platform_device *pdev)
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "failed to get IRQ\n");
|
||||
ret = irq;
|
||||
goto out_disable_clk;
|
||||
}
|
||||
|
Reference in New Issue
Block a user