diff options
author | John Crispin <john@openwrt.org> | 2011-10-10 15:13:46 +0000 |
---|---|---|
committer | John Crispin <john@openwrt.org> | 2011-10-10 15:13:46 +0000 |
commit | 0a866293bd9e204978c995cb0545c20f8ab63c7e (patch) | |
tree | 7d7a9ef25035a4afd4b371b85506fe062bac125a /target/linux/lantiq/patches-3.0/130-falcon-spi-flash.patch | |
parent | 1359fe4fcf0a6cef3eced837d63c866cc75a52fc (diff) | |
download | upstream-0a866293bd9e204978c995cb0545c20f8ab63c7e.tar.gz upstream-0a866293bd9e204978c995cb0545c20f8ab63c7e.tar.bz2 upstream-0a866293bd9e204978c995cb0545c20f8ab63c7e.zip |
* update patches to 3.0
* add basic vr9 support
* backport 3.1 fixes
* backport 3.2 queue (falcon)
SVN-Revision: 28405
Diffstat (limited to 'target/linux/lantiq/patches-3.0/130-falcon-spi-flash.patch')
-rw-r--r-- | target/linux/lantiq/patches-3.0/130-falcon-spi-flash.patch | 497 |
1 files changed, 0 insertions, 497 deletions
diff --git a/target/linux/lantiq/patches-3.0/130-falcon-spi-flash.patch b/target/linux/lantiq/patches-3.0/130-falcon-spi-flash.patch deleted file mode 100644 index cf618e046d..0000000000 --- a/target/linux/lantiq/patches-3.0/130-falcon-spi-flash.patch +++ /dev/null @@ -1,497 +0,0 @@ ---- a/drivers/spi/Makefile -+++ b/drivers/spi/Makefile -@@ -56,6 +56,7 @@ obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci. - obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o - obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o - obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o -+obj-$(CONFIG_SPI_FALCON) += spi_falcon.o - - # special build for s3c24xx spi driver with fiq support - spi_s3c24xx_hw-y := spi_s3c24xx.o ---- /dev/null -+++ b/drivers/spi/spi_falcon.c -@@ -0,0 +1,471 @@ -+/* -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -+ */ -+ -+#include <linux/module.h> -+#include <linux/device.h> -+#include <linux/platform_device.h> -+#include <linux/spi/spi.h> -+#include <linux/delay.h> -+#include <linux/workqueue.h> -+ -+#include <lantiq.h> /* ebu_lock */ -+#include <falcon/ebu_reg.h> -+#include <falcon/sys1_reg.h> -+ -+#define DRV_NAME "falcon_spi" -+ -+#define FALCON_SPI_XFER_BEGIN (1 << 0) -+#define FALCON_SPI_XFER_END (1 << 1) -+ -+/* mapping for access macros */ -+#define reg_r32(reg) __raw_readl(reg) -+#define reg_w32(val, reg) __raw_writel(val, reg) -+#define reg_w32_mask(clear, set, reg) reg_w32((reg_r32(reg) \ -+ & ~(clear)) | (set), reg) -+#define reg_r32_table(reg, idx) reg_r32(&((uint32_t *)®)[idx]) -+#define reg_w32_table(val, reg, idx) reg_w32(val, &((uint32_t *)®)[idx]) -+ -+#define ebu (priv->ebu_membase) -+#define sys1 (priv->sys1_membase) -+ -+struct falcon_spi { -+ u32 sfcmd; /* for caching of opcode, direction, ... */ -+ -+ struct spi_master *master; -+ -+ struct gpon_reg_ebu __iomem *ebu_membase; -+ struct gpon_reg_sys1 __iomem *sys1_membase; -+}; -+ -+int falcon_spi_xfer(struct spi_device *spi, -+ struct spi_transfer *t, -+ unsigned long flags) -+{ -+ struct device *dev = &spi->dev; -+ struct falcon_spi *priv = spi_master_get_devdata(spi->master); -+ const u8 *txp = t->tx_buf; -+ u8 *rxp = t->rx_buf; -+ unsigned int bytelen = ((8 * t->len + 7) / 8); -+ unsigned int len, alen, dumlen; -+ u32 val; -+ enum { -+ state_init, -+ state_command_prepare, -+ state_write, -+ state_read, -+ state_disable_cs, -+ state_end -+ } state = state_init; -+ -+ do { -+ switch (state) { -+ case state_init: /* detect phase of upper layer sequence */ -+ { -+ /* initial write ? */ -+ if (flags & FALCON_SPI_XFER_BEGIN) { -+ if (!txp) { -+ dev_err(dev, -+ "BEGIN without tx data!\n"); -+ return -1; -+ } -+ /* -+ * Prepare the parts of the sfcmd register, -+ * which should not -+ * change during a sequence! -+ * Only exception are the length fields, -+ * especially alen and dumlen. -+ */ -+ -+ priv->sfcmd = ((spi->chip_select -+ << SFCMD_CS_OFFSET) -+ & SFCMD_CS_MASK); -+ priv->sfcmd |= SFCMD_KEEP_CS_KEEP_SELECTED; -+ priv->sfcmd |= *txp; -+ txp++; -+ bytelen--; -+ if (bytelen) { -+ /* more data: -+ * maybe address and/or dummy */ -+ state = state_command_prepare; -+ break; -+ } else { -+ dev_dbg(dev, "write cmd %02X\n", -+ priv->sfcmd & SFCMD_OPC_MASK); -+ } -+ } -+ /* continued write ? */ -+ if (txp && bytelen) { -+ state = state_write; -+ break; -+ } -+ /* read data? */ -+ if (rxp && bytelen) { -+ state = state_read; -+ break; -+ } -+ /* end of sequence? */ -+ if (flags & FALCON_SPI_XFER_END) -+ state = state_disable_cs; -+ else -+ state = state_end; -+ break; -+ } -+ case state_command_prepare: /* collect tx data for -+ address and dummy phase */ -+ { -+ /* txp is valid, already checked */ -+ val = 0; -+ alen = 0; -+ dumlen = 0; -+ while (bytelen > 0) { -+ if (alen < 3) { -+ val = (val<<8)|(*txp++); -+ alen++; -+ } else if ((dumlen < 15) && (*txp == 0)) { -+ /* -+ * assume dummy bytes are set to 0 -+ * from upper layer -+ */ -+ dumlen++; -+ txp++; -+ } else -+ break; -+ bytelen--; -+ } -+ priv->sfcmd &= ~(SFCMD_ALEN_MASK | SFCMD_DUMLEN_MASK); -+ priv->sfcmd |= (alen << SFCMD_ALEN_OFFSET) | -+ (dumlen << SFCMD_DUMLEN_OFFSET); -+ if (alen > 0) -+ ebu_w32(val, sfaddr); -+ -+ dev_dbg(dev, "write cmd %02X, alen=%d " -+ "(addr=%06X) dumlen=%d\n", -+ priv->sfcmd & SFCMD_OPC_MASK, -+ alen, val, dumlen); -+ -+ if (bytelen > 0) { -+ /* continue with write */ -+ state = state_write; -+ } else if (flags & FALCON_SPI_XFER_END) { -+ /* end of sequence? */ -+ state = state_disable_cs; -+ } else { -+ /* go to end and expect another -+ * call (read or write) */ -+ state = state_end; -+ } -+ break; -+ } -+ case state_write: -+ { -+ /* txp still valid */ -+ priv->sfcmd |= SFCMD_DIR_WRITE; -+ len = 0; -+ val = 0; -+ do { -+ if (bytelen--) -+ val |= (*txp++) << (8 * len++); -+ if ((flags & FALCON_SPI_XFER_END) -+ && (bytelen == 0)) { -+ priv->sfcmd &= -+ ~SFCMD_KEEP_CS_KEEP_SELECTED; -+ } -+ if ((len == 4) || (bytelen == 0)) { -+ ebu_w32(val, sfdata); -+ ebu_w32(priv->sfcmd -+ | (len<<SFCMD_DLEN_OFFSET), -+ sfcmd); -+ len = 0; -+ val = 0; -+ priv->sfcmd &= ~(SFCMD_ALEN_MASK -+ | SFCMD_DUMLEN_MASK); -+ } -+ } while (bytelen); -+ state = state_end; -+ break; -+ } -+ case state_read: -+ { -+ /* read data */ -+ priv->sfcmd &= ~SFCMD_DIR_WRITE; -+ do { -+ if ((flags & FALCON_SPI_XFER_END) -+ && (bytelen <= 4)) { -+ priv->sfcmd &= -+ ~SFCMD_KEEP_CS_KEEP_SELECTED; -+ } -+ len = (bytelen > 4) ? 4 : bytelen; -+ bytelen -= len; -+ ebu_w32(priv->sfcmd -+ |(len<<SFCMD_DLEN_OFFSET), sfcmd); -+ priv->sfcmd &= ~(SFCMD_ALEN_MASK -+ | SFCMD_DUMLEN_MASK); -+ do { -+ val = ebu_r32(sfstat); -+ if (val & SFSTAT_CMD_ERR) { -+ /* reset error status */ -+ dev_err(dev, "SFSTAT: CMD_ERR " -+ "(%x)\n", val); -+ ebu_w32(SFSTAT_CMD_ERR, sfstat); -+ return -1; -+ } -+ } while (val & SFSTAT_CMD_PEND); -+ val = ebu_r32(sfdata); -+ do { -+ *rxp = (val & 0xFF); -+ rxp++; -+ val >>= 8; -+ len--; -+ } while (len); -+ } while (bytelen); -+ state = state_end; -+ break; -+ } -+ case state_disable_cs: -+ { -+ priv->sfcmd &= ~SFCMD_KEEP_CS_KEEP_SELECTED; -+ ebu_w32(priv->sfcmd | (0<<SFCMD_DLEN_OFFSET), sfcmd); -+ val = ebu_r32(sfstat); -+ if (val & SFSTAT_CMD_ERR) { -+ /* reset error status */ -+ dev_err(dev, "SFSTAT: CMD_ERR (%x)\n", val); -+ ebu_w32(SFSTAT_CMD_ERR, sfstat); -+ return -1; -+ } -+ state = state_end; -+ break; -+ } -+ case state_end: -+ break; -+ } -+ } while (state != state_end); -+ -+ return 0; -+} -+ -+static int falcon_spi_setup(struct spi_device *spi) -+{ -+ struct device *dev = &spi->dev; -+ struct falcon_spi *priv = spi_master_get_devdata(spi->master); -+ const u32 ebuclk = 100*1000*1000; -+ unsigned int i; -+ unsigned long flags; -+ -+ dev_dbg(dev, "setup\n"); -+ -+ if (spi->master->bus_num > 0 || spi->chip_select > 0) -+ return -ENODEV; -+ -+ spin_lock_irqsave(&ebu_lock, flags); -+ -+ if (ebuclk < spi->max_speed_hz) { -+ /* set EBU clock to 100 MHz */ -+ sys1_w32_mask(0, EBUCC_EBUDIV_SELF100, ebucc); -+ i = 1; /* divider */ -+ } else { -+ /* set EBU clock to 50 MHz */ -+ sys1_w32_mask(EBUCC_EBUDIV_SELF100, 0, ebucc); -+ -+ /* search for suitable divider */ -+ for (i = 1; i < 7; i++) { -+ if (ebuclk / i <= spi->max_speed_hz) -+ break; -+ } -+ } -+ -+ /* setup period of serial clock */ -+ ebu_w32_mask(SFTIME_SCKF_POS_MASK -+ | SFTIME_SCKR_POS_MASK -+ | SFTIME_SCK_PER_MASK, -+ (i << SFTIME_SCKR_POS_OFFSET) -+ | (i << (SFTIME_SCK_PER_OFFSET + 1)), -+ sftime); -+ -+ /* set some bits of unused_wd, to not trigger HOLD/WP -+ * signals on non QUAD flashes */ -+ ebu_w32((SFIO_UNUSED_WD_MASK & (0x8|0x4)), sfio); -+ -+ ebu_w32(BUSRCON0_AGEN_SERIAL_FLASH | BUSRCON0_PORTW_8_BIT_MUX, -+ busrcon0); -+ ebu_w32(BUSWCON0_AGEN_SERIAL_FLASH, buswcon0); -+ /* set address wrap around to maximum for 24-bit addresses */ -+ ebu_w32_mask(SFCON_DEV_SIZE_MASK, SFCON_DEV_SIZE_A23_0, sfcon); -+ -+ spin_unlock_irqrestore(&ebu_lock, flags); -+ -+ return 0; -+} -+ -+static int falcon_spi_transfer(struct spi_device *spi, struct spi_message *m) -+{ -+ struct falcon_spi *priv = spi_master_get_devdata(spi->master); -+ struct spi_transfer *t; -+ unsigned long spi_flags; -+ unsigned long flags; -+ int ret = 0; -+ -+ priv->sfcmd = 0; -+ m->actual_length = 0; -+ -+ spi_flags = FALCON_SPI_XFER_BEGIN; -+ list_for_each_entry(t, &m->transfers, transfer_list) { -+ if (list_is_last(&t->transfer_list, &m->transfers)) -+ spi_flags |= FALCON_SPI_XFER_END; -+ -+ spin_lock_irqsave(&ebu_lock, flags); -+ ret = falcon_spi_xfer(spi, t, spi_flags); -+ spin_unlock_irqrestore(&ebu_lock, flags); -+ -+ if (ret) -+ break; -+ -+ m->actual_length += t->len; -+ -+ if (t->delay_usecs || t->cs_change) -+ BUG(); -+ -+ spi_flags = 0; -+ } -+ -+ m->status = ret; -+ m->complete(m->context); -+ -+ return 0; -+} -+ -+static void falcon_spi_cleanup(struct spi_device *spi) -+{ -+ struct device *dev = &spi->dev; -+ -+ dev_dbg(dev, "cleanup\n"); -+} -+ -+static int __devinit falcon_spi_probe(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct falcon_spi *priv; -+ struct spi_master *master; -+ struct resource *memres_ebu, *memres_sys1; -+ int ret; -+ -+ dev_dbg(dev, "probing\n"); -+ -+ memres_ebu = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ebu"); -+ memres_sys1 = platform_get_resource_byname(pdev, IORESOURCE_MEM, -+ "sys1"); -+ -+ if (!memres_ebu || !memres_sys1) { -+ dev_err(dev, "no resources\n"); -+ return -ENODEV; -+ } -+ -+ master = spi_alloc_master(&pdev->dev, sizeof(*priv)); -+ if (!master) { -+ dev_err(dev, "no memory for spi_master\n"); -+ return -ENOMEM; -+ } -+ -+ priv = spi_master_get_devdata(master); -+ -+ priv->ebu_membase = ioremap_nocache(memres_ebu->start & ~KSEG1, -+ resource_size(memres_ebu)); -+ -+ if (!priv->ebu_membase) { -+ dev_err(dev, "can't map ebu memory\n"); -+ -+ ret = -ENOMEM; -+ goto free_master; -+ } -+ -+ priv->sys1_membase = ioremap_nocache(memres_sys1->start & ~KSEG1, -+ resource_size(memres_sys1)); -+ -+ if (!priv->sys1_membase) { -+ dev_err(dev, "can't map sys1 memory\n"); -+ -+ ret = -ENOMEM; -+ goto unmap_ebu; -+ } -+ -+ priv->master = master; -+ -+ master->mode_bits = SPI_MODE_3; -+ master->num_chipselect = 1; -+ master->bus_num = 0; -+ -+ master->setup = falcon_spi_setup; -+ master->transfer = falcon_spi_transfer; -+ master->cleanup = falcon_spi_cleanup; -+ -+ platform_set_drvdata(pdev, priv); -+ -+ ret = spi_register_master(master); -+ if (ret) -+ goto unmap_sys1; -+ -+ return 0; -+ -+unmap_sys1: -+ iounmap(priv->sys1_membase); -+ -+unmap_ebu: -+ iounmap(priv->ebu_membase); -+ -+free_master: -+ spi_master_put(master); -+ -+ return ret; -+} -+ -+static int __devexit falcon_spi_remove(struct platform_device *pdev) -+{ -+ struct device *dev = &pdev->dev; -+ struct falcon_spi *priv = platform_get_drvdata(pdev); -+ -+ dev_dbg(dev, "removed\n"); -+ -+ spi_unregister_master(priv->master); -+ -+ iounmap(priv->sys1_membase); -+ iounmap(priv->ebu_membase); -+ -+ return 0; -+} -+ -+static struct platform_driver falcon_spi_driver = { -+ .probe = falcon_spi_probe, -+ .remove = __devexit_p(falcon_spi_remove), -+ .driver = { -+ .name = DRV_NAME, -+ .owner = THIS_MODULE -+ } -+}; -+ -+static int __init falcon_spi_init(void) -+{ -+ return platform_driver_register(&falcon_spi_driver); -+} -+ -+static void __exit falcon_spi_exit(void) -+{ -+ platform_driver_unregister(&falcon_spi_driver); -+} -+ -+module_init(falcon_spi_init); -+module_exit(falcon_spi_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Lantiq Falcon SPI controller driver"); ---- a/drivers/spi/Kconfig -+++ b/drivers/spi/Kconfig -@@ -219,6 +219,10 @@ config SPI_MPC52xx - This drivers supports the MPC52xx SPI controller in master SPI - mode. - -+config SPI_FALCON -+ tristate "Falcon SPI controller support" -+ depends on SOC_FALCON -+ - config SPI_MPC52xx_PSC - tristate "Freescale MPC52xx PSC SPI controller" - depends on PPC_MPC52xx && EXPERIMENTAL |