diff options
Diffstat (limited to 'target/linux/ramips/patches-3.10/0019-SPI-ralink-add-Ralink-SoC-spi-driver.patch')
-rw-r--r-- | target/linux/ramips/patches-3.10/0019-SPI-ralink-add-Ralink-SoC-spi-driver.patch | 476 |
1 files changed, 0 insertions, 476 deletions
diff --git a/target/linux/ramips/patches-3.10/0019-SPI-ralink-add-Ralink-SoC-spi-driver.patch b/target/linux/ramips/patches-3.10/0019-SPI-ralink-add-Ralink-SoC-spi-driver.patch deleted file mode 100644 index d02ca67..0000000 --- a/target/linux/ramips/patches-3.10/0019-SPI-ralink-add-Ralink-SoC-spi-driver.patch +++ /dev/null @@ -1,476 +0,0 @@ -From 43c36279a0e822de608c1e825826bbac3238d8a2 Mon Sep 17 00:00:00 2001 -From: Gabor Juhos <juhosg@openwrt.org> -Date: Mon, 22 Apr 2013 23:16:18 +0200 -Subject: [PATCH 19/25] SPI: ralink: add Ralink SoC spi driver - -Add the driver needed to make SPI work on Ralink SoC. - -Signed-off-by: Gabor Juhos <juhosg@openwrt.org> -Acked-by: John Crispin <blogic@openwrt.org> ---- - drivers/spi/Kconfig | 6 + - drivers/spi/Makefile | 1 + - drivers/spi/spi-rt2880.c | 450 ++++++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 457 insertions(+) - create mode 100644 drivers/spi/spi-rt2880.c - ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -354,6 +354,12 @@ config SPI_RSPI - help - SPI driver for Renesas RSPI blocks. - -+config SPI_RT2880 -+ tristate "Ralink RT288x SPI Controller" -+ depends on RALINK -+ help -+ This selects a driver for the Ralink RT288x/RT305x SPI Controller. -+ - config SPI_S3C24XX - tristate "Samsung S3C24XX series SPI" - depends on ARCH_S3C24XX ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -56,6 +56,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_ - obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o - obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o - obj-$(CONFIG_SPI_RSPI) += spi-rspi.o -+obj-$(CONFIG_SPI_RT2880) += spi-rt2880.o - obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o - spi-s3c24xx-hw-y := spi-s3c24xx.o - spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o ---- /dev/null -+++ b/drivers/spi/spi-rt2880.c -@@ -0,0 +1,432 @@ -+/* -+ * spi-rt2880.c -- Ralink RT288x/RT305x SPI controller driver -+ * -+ * Copyright (C) 2011 Sergiy <piratfm@gmail.com> -+ * Copyright (C) 2011-2013 Gabor Juhos <juhosg@openwrt.org> -+ * -+ * Some parts are based on spi-orion.c: -+ * Author: Shadi Ammouri <shadi@marvell.com> -+ * Copyright (C) 2007-2008 Marvell Ltd. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/clk.h> -+#include <linux/err.h> -+#include <linux/delay.h> -+#include <linux/io.h> -+#include <linux/reset.h> -+#include <linux/spi/spi.h> -+#include <linux/platform_device.h> -+ -+#define DRIVER_NAME "spi-rt2880" -+/* only one slave is supported*/ -+#define RALINK_NUM_CHIPSELECTS 1 -+/* in usec */ -+#define RALINK_SPI_WAIT_MAX_LOOP 2000 -+ -+#define RAMIPS_SPI_STAT 0x00 -+#define RAMIPS_SPI_CFG 0x10 -+#define RAMIPS_SPI_CTL 0x14 -+#define RAMIPS_SPI_DATA 0x20 -+#define RAMIPS_SPI_FIFO_STAT 0x38 -+ -+/* SPISTAT register bit field */ -+#define SPISTAT_BUSY BIT(0) -+ -+/* SPICFG register bit field */ -+#define SPICFG_LSBFIRST 0 -+#define SPICFG_MSBFIRST BIT(8) -+#define SPICFG_SPICLKPOL BIT(6) -+#define SPICFG_RXCLKEDGE_FALLING BIT(5) -+#define SPICFG_TXCLKEDGE_FALLING BIT(4) -+#define SPICFG_SPICLK_PRESCALE_MASK 0x7 -+#define SPICFG_SPICLK_DIV2 0 -+#define SPICFG_SPICLK_DIV4 1 -+#define SPICFG_SPICLK_DIV8 2 -+#define SPICFG_SPICLK_DIV16 3 -+#define SPICFG_SPICLK_DIV32 4 -+#define SPICFG_SPICLK_DIV64 5 -+#define SPICFG_SPICLK_DIV128 6 -+#define SPICFG_SPICLK_DISABLE 7 -+ -+/* SPICTL register bit field */ -+#define SPICTL_HIZSDO BIT(3) -+#define SPICTL_STARTWR BIT(2) -+#define SPICTL_STARTRD BIT(1) -+#define SPICTL_SPIENA BIT(0) -+ -+/* SPIFIFOSTAT register bit field */ -+#define SPIFIFOSTAT_TXFULL BIT(17) -+ -+struct rt2880_spi { -+ struct spi_master *master; -+ void __iomem *base; -+ unsigned int sys_freq; -+ unsigned int speed; -+ struct clk *clk; -+ spinlock_t lock; -+}; -+ -+static inline struct rt2880_spi *spidev_to_rt2880_spi(struct spi_device *spi) -+{ -+ return spi_master_get_devdata(spi->master); -+} -+ -+static inline u32 rt2880_spi_read(struct rt2880_spi *rs, u32 reg) -+{ -+ return ioread32(rs->base + reg); -+} -+ -+static inline void rt2880_spi_write(struct rt2880_spi *rs, u32 reg, u32 val) -+{ -+ iowrite32(val, rs->base + reg); -+} -+ -+static inline void rt2880_spi_setbits(struct rt2880_spi *rs, u32 reg, u32 mask) -+{ -+ void __iomem *addr = rs->base + reg; -+ unsigned long flags; -+ u32 val; -+ -+ spin_lock_irqsave(&rs->lock, flags); -+ val = ioread32(addr); -+ val |= mask; -+ iowrite32(val, addr); -+ spin_unlock_irqrestore(&rs->lock, flags); -+} -+ -+static inline void rt2880_spi_clrbits(struct rt2880_spi *rs, u32 reg, u32 mask) -+{ -+ void __iomem *addr = rs->base + reg; -+ unsigned long flags; -+ u32 val; -+ -+ spin_lock_irqsave(&rs->lock, flags); -+ val = ioread32(addr); -+ val &= ~mask; -+ iowrite32(val, addr); -+ spin_unlock_irqrestore(&rs->lock, flags); -+} -+ -+static int rt2880_spi_baudrate_set(struct spi_device *spi, unsigned int speed) -+{ -+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi); -+ u32 rate; -+ u32 prescale; -+ u32 reg; -+ -+ dev_dbg(&spi->dev, "speed:%u\n", speed); -+ -+ /* -+ * the supported rates are: 2, 4, 8, ... 128 -+ * round up as we look for equal or less speed -+ */ -+ rate = DIV_ROUND_UP(rs->sys_freq, speed); -+ dev_dbg(&spi->dev, "rate-1:%u\n", rate); -+ rate = roundup_pow_of_two(rate); -+ dev_dbg(&spi->dev, "rate-2:%u\n", rate); -+ -+ /* check if requested speed is too small */ -+ if (rate > 128) -+ return -EINVAL; -+ -+ if (rate < 2) -+ rate = 2; -+ -+ /* Convert the rate to SPI clock divisor value. */ -+ prescale = ilog2(rate / 2); -+ dev_dbg(&spi->dev, "prescale:%u\n", prescale); -+ -+ reg = rt2880_spi_read(rs, RAMIPS_SPI_CFG); -+ reg = ((reg & ~SPICFG_SPICLK_PRESCALE_MASK) | prescale); -+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, reg); -+ rs->speed = speed; -+ return 0; -+} -+ -+/* -+ * called only when no transfer is active on the bus -+ */ -+static int -+rt2880_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) -+{ -+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi); -+ unsigned int speed = spi->max_speed_hz; -+ int rc; -+ -+ if ((t != NULL) && t->speed_hz) -+ speed = t->speed_hz; -+ -+ if (rs->speed != speed) { -+ dev_dbg(&spi->dev, "speed_hz:%u\n", speed); -+ rc = rt2880_spi_baudrate_set(spi, speed); -+ if (rc) -+ return rc; -+ } -+ -+ return 0; -+} -+ -+static void rt2880_spi_set_cs(struct rt2880_spi *rs, int enable) -+{ -+ if (enable) -+ rt2880_spi_clrbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA); -+ else -+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_SPIENA); -+} -+ -+static inline int rt2880_spi_wait_till_ready(struct rt2880_spi *rs) -+{ -+ int i; -+ -+ for (i = 0; i < RALINK_SPI_WAIT_MAX_LOOP; i++) { -+ u32 status; -+ -+ status = rt2880_spi_read(rs, RAMIPS_SPI_STAT); -+ if ((status & SPISTAT_BUSY) == 0) -+ return 0; -+ -+ cpu_relax(); -+ udelay(1); -+ } -+ -+ return -ETIMEDOUT; -+} -+ -+static unsigned int -+rt2880_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) -+{ -+ 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; -+ -+ dev_dbg(&spi->dev, "read (%d): %s %s\n", xfer->len, -+ (tx != NULL) ? "tx" : " ", -+ (rx != NULL) ? "rx" : " "); -+ -+ if (tx) { -+ for (count = 0; count < xfer->len; count++) { -+ rt2880_spi_write(rs, RAMIPS_SPI_DATA, tx[count]); -+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTWR); -+ err = rt2880_spi_wait_till_ready(rs); -+ if (err) { -+ dev_err(&spi->dev, "TX failed, err=%d\n", err); -+ goto out; -+ } -+ } -+ } -+ -+ if (rx) { -+ for (count = 0; count < xfer->len; count++) { -+ rt2880_spi_setbits(rs, RAMIPS_SPI_CTL, SPICTL_STARTRD); -+ err = rt2880_spi_wait_till_ready(rs); -+ if (err) { -+ dev_err(&spi->dev, "RX failed, err=%d\n", err); -+ goto out; -+ } -+ rx[count] = (u8) rt2880_spi_read(rs, RAMIPS_SPI_DATA); -+ } -+ } -+ -+out: -+ return count; -+} -+ -+static int rt2880_spi_transfer_one_message(struct spi_master *master, -+ struct spi_message *m) -+{ -+ struct rt2880_spi *rs = spi_master_get_devdata(master); -+ struct spi_device *spi = m->spi; -+ struct spi_transfer *t = NULL; -+ int par_override = 0; -+ int status = 0; -+ int cs_active = 0; -+ -+ /* Load defaults */ -+ status = rt2880_spi_setup_transfer(spi, NULL); -+ if (status < 0) -+ goto msg_done; -+ -+ 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 (t->speed_hz && t->speed_hz < (rs->sys_freq / 128)) { -+ dev_err(&spi->dev, -+ "message rejected: device min speed (%d Hz) exceeds required transfer speed (%d Hz)\n", -+ (rs->sys_freq / 128), t->speed_hz); -+ status = -EIO; -+ goto msg_done; -+ } -+ -+ if (par_override || t->speed_hz || t->bits_per_word) { -+ par_override = 1; -+ status = rt2880_spi_setup_transfer(spi, t); -+ if (status < 0) -+ goto msg_done; -+ if (!t->speed_hz && !t->bits_per_word) -+ par_override = 0; -+ } -+ -+ 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); -+ -+ return 0; -+} -+ -+static int rt2880_spi_setup(struct spi_device *spi) -+{ -+ struct rt2880_spi *rs = spidev_to_rt2880_spi(spi); -+ -+ if ((spi->max_speed_hz == 0) || -+ (spi->max_speed_hz > (rs->sys_freq / 2))) -+ spi->max_speed_hz = (rs->sys_freq / 2); -+ -+ if (spi->max_speed_hz < (rs->sys_freq / 128)) { -+ dev_err(&spi->dev, "setup: requested speed is too low %d Hz\n", -+ spi->max_speed_hz); -+ return -EINVAL; -+ } -+ -+ /* -+ * baudrate & width will be set rt2880_spi_setup_transfer -+ */ -+ return 0; -+} -+ -+static void rt2880_spi_reset(struct rt2880_spi *rs) -+{ -+ rt2880_spi_write(rs, RAMIPS_SPI_CFG, -+ SPICFG_MSBFIRST | SPICFG_TXCLKEDGE_FALLING | -+ SPICFG_SPICLK_DIV16 | SPICFG_SPICLKPOL); -+ rt2880_spi_write(rs, RAMIPS_SPI_CTL, SPICTL_HIZSDO | SPICTL_SPIENA); -+} -+ -+static int rt2880_spi_probe(struct platform_device *pdev) -+{ -+ struct spi_master *master; -+ struct rt2880_spi *rs; -+ unsigned long flags; -+ void __iomem *base; -+ struct resource *r; -+ int status = 0; -+ struct clk *clk; -+ -+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); -+ base = devm_ioremap_resource(&pdev->dev, r); -+ if (IS_ERR(base)) -+ return PTR_ERR(base); -+ -+ clk = devm_clk_get(&pdev->dev, NULL); -+ if (IS_ERR(clk)) { -+ dev_err(&pdev->dev, "unable to get SYS clock, err=%d\n", -+ status); -+ return PTR_ERR(clk); -+ } -+ -+ status = clk_prepare_enable(clk); -+ if (status) -+ return status; -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(*rs)); -+ if (master == NULL) { -+ dev_dbg(&pdev->dev, "master allocation failed\n"); -+ return -ENOMEM; -+ } -+ -+ /* we support only mode 0, and no options */ -+ master->mode_bits = 0; -+ -+ master->setup = rt2880_spi_setup; -+ master->transfer_one_message = rt2880_spi_transfer_one_message; -+ master->num_chipselect = RALINK_NUM_CHIPSELECTS; -+ master->bits_per_word_mask = SPI_BPW_MASK(8); -+ master->dev.of_node = pdev->dev.of_node; -+ -+ dev_set_drvdata(&pdev->dev, master); -+ -+ rs = spi_master_get_devdata(master); -+ rs->base = base; -+ rs->clk = clk; -+ rs->master = master; -+ rs->sys_freq = clk_get_rate(rs->clk); -+ dev_dbg(&pdev->dev, "sys_freq: %u\n", rs->sys_freq); -+ spin_lock_irqsave(&rs->lock, flags); -+ -+ device_reset(&pdev->dev); -+ -+ rt2880_spi_reset(rs); -+ -+ return spi_register_master(master); -+} -+ -+static int rt2880_spi_remove(struct platform_device *pdev) -+{ -+ struct spi_master *master; -+ struct rt2880_spi *rs; -+ -+ master = dev_get_drvdata(&pdev->dev); -+ rs = spi_master_get_devdata(master); -+ -+ clk_disable(rs->clk); -+ spi_unregister_master(master); -+ -+ return 0; -+} -+ -+MODULE_ALIAS("platform:" DRIVER_NAME); -+ -+static const struct of_device_id rt2880_spi_match[] = { -+ { .compatible = "ralink,rt2880-spi" }, -+ {}, -+}; -+MODULE_DEVICE_TABLE(of, rt2880_spi_match); -+ -+static struct platform_driver rt2880_spi_driver = { -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ .of_match_table = rt2880_spi_match, -+ }, -+ .probe = rt2880_spi_probe, -+ .remove = rt2880_spi_remove, -+}; -+ -+module_platform_driver(rt2880_spi_driver); -+ -+MODULE_DESCRIPTION("Ralink SPI driver"); -+MODULE_AUTHOR("Sergiy <piratfm@gmail.com>"); -+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>"); -+MODULE_LICENSE("GPL"); |