aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch127
1 files changed, 62 insertions, 65 deletions
diff --git a/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch b/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch
index 862e24c368..57986d33fe 100644
--- a/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch
+++ b/target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch
@@ -41,7 +41,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
--- /dev/null
+++ b/drivers/spi/spi-rt2880.c
-@@ -0,0 +1,533 @@
+@@ -0,0 +1,530 @@
+/*
+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver
+ *
@@ -66,10 +66,9 @@ Acked-by: John Crispin <blogic@openwrt.org>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
++#include <linux/gpio.h>
+
+#define DRIVER_NAME "spi-rt2880"
-+/* only one slave is supported*/
-+#define RALINK_NUM_CHIPSELECTS 1
+
+#define RAMIPS_SPI_STAT 0x00
+#define RAMIPS_SPI_CFG 0x10
@@ -169,6 +168,8 @@ Acked-by: John Crispin <blogic@openwrt.org>
+#define RT2880_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | \
+ SPI_CS_HIGH)
+
++static atomic_t hw_reset_count = ATOMIC_INIT(0);
++
+struct rt2880_spi {
+ struct spi_master *master;
+ void __iomem *base;
@@ -248,12 +249,14 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ return offset;
+}
+
-+static void rt2880_spi_set_cs(struct rt2880_spi *rs, int enable)
++static void rt2880_spi_set_cs(struct spi_device *spi, bool enable)
+{
++ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
++
+ if (enable)
-+ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
-+ else
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
++ else
++ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA);
+}
+
+static int rt2880_spi_wait_ready(struct rt2880_spi *rs, int len)
@@ -269,22 +272,41 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ return -ETIMEDOUT;
+}
+
-+static unsigned int
-+rt2880_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer)
++static void rt2880_dump_reg(struct spi_master *master)
+{
-+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi);
-+ unsigned count = 0;
-+ u8 *rx = xfer->rx_buf;
-+ const u8 *tx = xfer->tx_buf;
-+ int err;
++ struct rt2880_spi *rs = spi_master_get_devdata(master);
+
-+ dev_dbg(&spi->dev, "read (%d): %s %s\n", xfer->len,
-+ (tx != NULL) ? "tx" : " ",
-+ (rx != NULL) ? "rx" : " ");
++ dev_dbg(&master->dev, "stat: %08x, cfg: %08x, ctl: %08x, " \
++ "data: %08x, arb: %08x\n",
++ rt2880_spi_read(rs, RAMIPS_SPI_STAT),
++ rt2880_spi_read(rs, RAMIPS_SPI_CFG),
++ rt2880_spi_read(rs, RAMIPS_SPI_CTL),
++ rt2880_spi_read(rs, RAMIPS_SPI_DATA),
++ rt2880_spi_read(rs, get_arbiter_offset(master)));
++}
++
++static int rt2880_spi_transfer_one(struct spi_master *master,
++ struct spi_device *spi, struct spi_transfer *xfer)
++{
++ struct rt2880_spi *rs = spi_master_get_devdata(master);
++ unsigned len;
++ const u8 *tx = xfer->tx_buf;
++ u8 *rx = xfer->rx_buf;
++ int err = 0;
++
++ /* change clock speed */
++ if (unlikely(rs->speed != xfer->speed_hz)) {
++ u32 reg;
++ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG);
++ reg &= ~SPICFG_SPICLK_PRESCALE_MASK;
++ reg |= rt2880_spi_baudrate_get(spi, xfer->speed_hz);
++ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg);
++ }
+
+ if (tx) {
-+ for (count = 0; count < xfer->len; count++) {
-+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, tx[count]);
++ len = xfer->len;
++ while (len-- > 0) {
++ rt2880_spi_write(rs, RAMIPS_SPI_DATA, *tx++);
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR);
+ err = rt2880_spi_wait_ready(rs, 1);
+ if (err) {
@@ -295,63 +317,32 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ }
+
+ if (rx) {
-+ for (count = 0; count < xfer->len; count++) {
++ len = xfer->len;
++ while (len-- > 0) {
+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD);
+ err = rt2880_spi_wait_ready(rs, 1);
+ if (err) {
+ dev_err(&spi->dev, "RX failed, err=%d\n", err);
+ goto out;
+ }
-+ rx[count] = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
++ *rx++ = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA);
+ }
+ }
+
+out:
-+ return count;
++ return err;
+}
+
-+static int rt2880_spi_transfer_one_message(struct spi_master *master,
-+ struct spi_message *m)
++/* copy from spi.c */
++static void spi_set_cs(struct spi_device *spi, bool enable)
+{
-+ struct rt2880_spi *rs = spi_master_get_devdata(master);
-+ struct spi_device *spi = m->spi;
-+ struct spi_transfer *t = NULL;
-+ int status = 0;
-+ int cs_active = 0;
-+
-+ list_for_each_entry(t, &m->transfers, transfer_list) {
-+ if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
-+ dev_err(&spi->dev,
-+ "message rejected: invalid transfer data buffers\n");
-+ status = -EIO;
-+ goto msg_done;
-+ }
-+
-+ if (!cs_active) {
-+ rt2880_spi_set_cs(rs, 1);
-+ cs_active = 1;
-+ }
-+
-+ if (t->len)
-+ m->actual_length += rt2880_spi_write_read(spi, t);
-+
-+ if (t->delay_usecs)
-+ udelay(t->delay_usecs);
-+
-+ if (t->cs_change) {
-+ rt2880_spi_set_cs(rs, 0);
-+ cs_active = 0;
-+ }
-+ }
-+
-+msg_done:
-+ if (cs_active)
-+ rt2880_spi_set_cs(rs, 0);
-+
-+ m->status = status;
-+ spi_finalize_current_message(master);
++ if (spi->mode & SPI_CS_HIGH)
++ enable = !enable;
+
-+ return 0;
++ if (spi->cs_gpio >= 0)
++ gpio_set_value(spi->cs_gpio, !enable);
++ else if (spi->master->set_cs)
++ spi->master->set_cs(spi, !enable);
+}
+
+static int rt2880_spi_setup(struct spi_device *spi)
@@ -410,6 +401,11 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ if (reg != old_reg)
+ rt2880_spi_write(rs, arbit_off, reg);
+
++ /* deselected the spi device */
++ spi_set_cs(spi, false);
++
++ rt2880_dump_reg(master);
++
+ return 0;
+}
+
@@ -508,8 +504,8 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ master->flags = SPI_MASTER_HALF_DUPLEX;
+ master->setup = rt2880_spi_setup;
+ master->prepare_message = rt2880_spi_prepare_message;
-+ master->transfer_one_message = rt2880_spi_transfer_one_message;
-+ master->num_chipselect = RALINK_NUM_CHIPSELECTS;
++ master->set_cs = rt2880_spi_set_cs;
++ master->transfer_one = rt2880_spi_transfer_one,
+
+ dev_set_drvdata(&pdev->dev, master);
+
@@ -518,8 +514,8 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ rs->base = base;
+ rs->clk = clk;
+
-+ device_reset(&pdev->dev);
-+
++ if (atomic_inc_return(&hw_reset_count) == 1)
++ device_reset(&pdev->dev);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret < 0) {
@@ -547,6 +543,7 @@ Acked-by: John Crispin <blogic@openwrt.org>
+ rs = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(rs->clk);
++ atomic_dec(&hw_reset_count);
+
+ return 0;
+}