summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@libc.org>2016-08-10 15:00:24 +0000
committerRich Felker <dalias@libc.org>2016-08-10 15:00:24 +0000
commit425d3132a597f635e208769f0134f0d0625a4974 (patch)
tree1bdcae0385ac727956c3a9d1113fcc3a16b1239d
parent76c8129e8ebc4408f209b4ac4ee843356db1b5ae (diff)
downloadlinux-sh-425d3132a597f635e208769f0134f0d0625a4974.tar.gz
spi/jcore: backport changes sent upstream for 4.8
Signed-off-by: Rich Felker <dalias@libc.org>
-rw-r--r--drivers/spi/spi-jcore.c125
1 files changed, 71 insertions, 54 deletions
diff --git a/drivers/spi/spi-jcore.c b/drivers/spi/spi-jcore.c
index 7e7b3b38710c..7d2044a106a2 100644
--- a/drivers/spi/spi-jcore.c
+++ b/drivers/spi/spi-jcore.c
@@ -13,23 +13,17 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/delay.h>
-#define DRV_NAME "jcore_spi"
-
-#define MAX_SPI_SPEED 12500000 /* 12.5 MHz */
+#define DRV_NAME "jcore_spi"
#define CTRL_REG 0x0
#define DATA_REG 0x4
-#define SPI_NOCHIP_CS 0
-#define SPI_FLASH_CS 1
-#define SPI_CONF_CS 2
-#define SPI_SD_CS 2
-#define SPI_CODEC_CS 3
-
#define JCORE_SPI_CTRL_XMIT 0x02
#define JCORE_SPI_STAT_BUSY 0x02
#define JCORE_SPI_CTRL_LOOP 0x08
@@ -40,27 +34,34 @@
struct jcore_spi {
struct spi_master *master;
void __iomem *base;
- volatile unsigned int ctrlReg;
- unsigned int csReg;
- unsigned int speedReg;
+ unsigned int cs_reg;
+ unsigned int speed_reg;
unsigned int speed_hz;
+ unsigned int clock_freq;
};
-static void jcore_spi_wait_till_ready(struct jcore_spi *hw, int timeout)
+static int jcore_spi_wait(void __iomem *ctrl_reg)
{
- while (timeout--) {
- hw->ctrlReg = readl(hw->base + CTRL_REG);
- if (!(hw->ctrlReg & JCORE_SPI_STAT_BUSY))
- return;
+ unsigned timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP;
+
+ do {
+ if (!(readl(ctrl_reg) & JCORE_SPI_STAT_BUSY))
+ return 0;
cpu_relax();
- }
- dev_err(hw->master->dev.parent, "%s: Timeout..\n", __func__);
+ } while (--timeout);
+
+ return -EBUSY;
}
static void jcore_spi_program(struct jcore_spi *hw)
{
- jcore_spi_wait_till_ready(hw, JCORE_SPI_WAIT_RDY_MAX_LOOP);
- writel(hw->csReg | hw->speedReg, hw->base + CTRL_REG);
+ void __iomem *ctrl_reg = hw->base + CTRL_REG;
+
+ if (jcore_spi_wait(ctrl_reg))
+ dev_err(hw->master->dev.parent,
+ "timeout waiting to program ctrl reg.\n");
+
+ writel(hw->cs_reg | hw->speed_reg, ctrl_reg);
}
static void jcore_spi_chipsel(struct spi_device *spi, bool value)
@@ -68,12 +69,12 @@ static void jcore_spi_chipsel(struct spi_device *spi, bool value)
struct jcore_spi *hw = spi_master_get_devdata(spi->master);
u32 csbit = 1U << (2 * spi->chip_select);
- dev_dbg(hw->master->dev.parent, "%s: CS=%d\n", __func__, value);
+ dev_dbg(hw->master->dev.parent, "chipselect %d\n", spi->chip_select);
if (value)
- hw->csReg |= csbit;
+ hw->cs_reg |= csbit;
else
- hw->csReg &= ~csbit;
+ hw->cs_reg &= ~csbit;
jcore_spi_program(hw);
}
@@ -82,10 +83,13 @@ static void jcore_spi_baudrate(struct jcore_spi *hw, int speed)
{
if (speed == hw->speed_hz) return;
hw->speed_hz = speed;
- hw->speedReg = ((MAX_SPI_SPEED / speed) - 1) << 27;
+ if (speed >= hw->clock_freq / 2)
+ hw->speed_reg = 0;
+ else
+ hw->speed_reg = ((hw->clock_freq / 2 / speed) - 1) << 27;
jcore_spi_program(hw);
- dev_dbg(hw->master->dev.parent, "%s: speed=%d pre=0x%x\n",
- __func__, speed, hw->speedReg);
+ dev_dbg(hw->master->dev.parent, "speed=%d reg=0x%x\n",
+ speed, hw->speed_reg);
}
static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
@@ -93,11 +97,9 @@ static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
{
struct jcore_spi *hw = spi_master_get_devdata(master);
- void *ctrl_reg = hw->base + CTRL_REG;
- void *data_reg = hw->base + DATA_REG;
- unsigned int timeout;
+ void __iomem *ctrl_reg = hw->base + CTRL_REG;
+ void __iomem *data_reg = hw->base + DATA_REG;
u32 xmit;
- u32 status;
/* data buffers */
const unsigned char *tx;
@@ -107,27 +109,19 @@ static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
jcore_spi_baudrate(hw, t->speed_hz);
- xmit = hw->csReg | hw->speedReg | JCORE_SPI_CTRL_XMIT;
+ xmit = hw->cs_reg | hw->speed_reg | JCORE_SPI_CTRL_XMIT;
tx = t->tx_buf;
rx = t->rx_buf;
len = t->len;
for (count = 0; count < len; count++) {
- timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP;
- do {
- status = readl(ctrl_reg);
- } while ((status & JCORE_SPI_STAT_BUSY) && --timeout);
- if (!timeout)
+ if (jcore_spi_wait(ctrl_reg))
break;
writel(tx ? *tx++ : 0, data_reg);
writel(xmit, ctrl_reg);
- timeout = JCORE_SPI_WAIT_RDY_MAX_LOOP;
- do {
- status = readl(ctrl_reg);
- } while ((status & JCORE_SPI_STAT_BUSY) && --timeout);
- if (!timeout)
+ if (jcore_spi_wait(ctrl_reg))
break;
if (rx)
@@ -136,7 +130,10 @@ static int jcore_spi_txrx(struct spi_master *master, struct spi_device *spi,
spi_finalize_current_transfer(master);
- return count<len ? -EREMOTEIO : 0;
+ if (count < len)
+ return -EREMOTEIO;
+
+ return 0;
}
static int jcore_spi_probe(struct platform_device *pdev)
@@ -145,45 +142,64 @@ static int jcore_spi_probe(struct platform_device *pdev)
struct jcore_spi *hw;
struct spi_master *master;
struct resource *res;
+ u32 clock_freq;
+ struct clk *clk;
int err = -ENODEV;
master = spi_alloc_master(&pdev->dev, sizeof(struct jcore_spi));
if (!master)
return err;
- /* setup the master state. */
+ /* Setup the master state. */
master->num_chipselect = 3;
- master->mode_bits = SPI_MODE_3;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->transfer_one = jcore_spi_txrx;
master->set_cs = jcore_spi_chipsel;
master->dev.of_node = node;
+ master->bus_num = pdev->id;
hw = spi_master_get_devdata(master);
hw->master = master;
platform_set_drvdata(pdev, hw);
- /* find and map our resources */
+ /* Find and map our resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
goto exit_busy;
- if (!devm_request_mem_region
- (&pdev->dev, res->start, resource_size(res), pdev->name))
+ if (!devm_request_mem_region(&pdev->dev, res->start,
+ resource_size(res), pdev->name))
goto exit_busy;
- hw->base =
- devm_ioremap_nocache(&pdev->dev, res->start, resource_size(res));
+ hw->base = devm_ioremap_nocache(&pdev->dev, res->start,
+ resource_size(res));
if (!hw->base)
goto exit_busy;
+ /*
+ * The SPI clock rate controlled via a configurable clock divider
+ * which is applied to the reference clock. A 50 MHz reference is
+ * most suitable for obtaining standard SPI clock rates, but some
+ * designs may have a different reference clock, and the DT must
+ * make the driver aware so that it can properly program the
+ * requested rate. If the clock is omitted, 50 MHz is assumed.
+ */
+ clock_freq = 50000000;
+ clk = devm_clk_get(&pdev->dev, "ref_clk");
+ if (!IS_ERR_OR_NULL(clk)) {
+ if (clk_enable(clk) == 0)
+ clock_freq = clk_get_rate(clk);
+ else
+ dev_warn(&pdev->dev, "could not enable ref_clk\n");
+ }
+ hw->clock_freq = clock_freq;
+
/* Initialize all CS bits to high. */
- hw->csReg = JCORE_SPI_CTRL_CS_BITS;
+ hw->cs_reg = JCORE_SPI_CTRL_CS_BITS;
jcore_spi_baudrate(hw, 400000);
- pdev->dev.dma_mask = 0;
- /* register our spi controller */
+ /* Register our spi controller */
err = devm_spi_register_master(&pdev->dev, master);
if (err)
goto exit;
- dev_info(&pdev->dev, "base %p, noirq\n", hw->base);
return 0;
@@ -212,4 +228,5 @@ module_platform_driver(jcore_spi_driver);
MODULE_DESCRIPTION("J-Core SPI driver");
MODULE_AUTHOR("Rich Felker <dalias@libc.org>");
+MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRV_NAME);