diff options
Diffstat (limited to 'target/linux/ramips')
-rw-r--r-- | target/linux/ramips/patches-3.18/0050-SPI-ralink-add-Ralink-SoC-spi-driver.patch | 127 |
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; +} |