From patchwork Wed Feb 3 10:21:57 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hemanth V X-Patchwork-Id: 76679 Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o13AM7So018006 for ; Wed, 3 Feb 2010 10:22:45 GMT Received: from localhost ([127.0.0.1] helo=sfs-ml-2.v29.ch3.sourceforge.com) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1NccN5-0003DU-KS; Wed, 03 Feb 2010 10:22:07 +0000 Received: from sfi-mx-4.v28.ch3.sourceforge.com ([172.29.28.124] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1NccN4-0003DA-4r for spi-devel-general@lists.sourceforge.net; Wed, 03 Feb 2010 10:22:06 +0000 Received-SPF: pass (sfi-mx-4.v28.ch3.sourceforge.com: domain of ti.com designates 192.94.94.40 as permitted sender) client-ip=192.94.94.40; envelope-from=hemanthv@ti.com; helo=arroyo.ext.ti.com; Received: from arroyo.ext.ti.com ([192.94.94.40]) by sfi-mx-4.v28.ch3.sourceforge.com with esmtps (TLSv1:AES256-SHA:256) (Exim 4.69) id 1NccN2-0000yT-Ms for spi-devel-general@lists.sourceforge.net; Wed, 03 Feb 2010 10:22:05 +0000 Received: from dlep34.itg.ti.com ([157.170.170.115]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id o13ALwpk005628 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 3 Feb 2010 04:21:58 -0600 Received: from dbdmail.itg.ti.com (localhost [127.0.0.1]) by dlep34.itg.ti.com (8.13.7/8.13.7) with ESMTP id o13ALtMZ026518; Wed, 3 Feb 2010 04:21:56 -0600 (CST) Received: from 10.24.255.17 (SquirrelMail authenticated user x0099946); by dbdmail.itg.ti.com with HTTP; Wed, 3 Feb 2010 15:51:57 +0530 (IST) Message-ID: <9697.10.24.255.17.1265192517.squirrel@dbdmail.itg.ti.com> Date: Wed, 3 Feb 2010 15:51:57 +0530 (IST) From: "Hemanth V" To: spi-devel-general@lists.sourceforge.net User-Agent: SquirrelMail/1.4.3a X-Mailer: SquirrelMail/1.4.3a MIME-Version: 1.0 X-Priority: 3 (Normal) Importance: Normal References: In-Reply-To: X-Spam-Score: -1.5 (-) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -1.5 SPF_CHECK_PASS SPF reports sender host as permitted sender for sender-domain -0.0 SPF_PASS SPF: sender matches SPF record X-Headers-End: 1NccN2-0000yT-Ms Cc: dbrownell@users.sourceforge.net, linux-omap@vger.kernel.org Subject: [spi-devel-general] PATCH[V2 2/3]: Adds support for FIFO X-BeenThere: spi-devel-general@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux SPI core/device drivers discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: spi-devel-general-bounces@lists.sourceforge.net X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 03 Feb 2010 10:22:45 +0000 (UTC) diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index 121cdd2..ce02f50 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -37,10 +37,11 @@ #include #include +#include #define OMAP2_MCSPI_MAX_FREQ 48000000 - +#define OMAP2_MCSPI_MAX_FIFODEPTH 64 /* OMAP2 has 3 SPI controllers, while OMAP3 has 4 */ #define OMAP2_MCSPI_MAX_CTRL 4 @@ -52,6 +53,7 @@ #define OMAP2_MCSPI_WAKEUPENABLE 0x20 #define OMAP2_MCSPI_SYST 0x24 #define OMAP2_MCSPI_MODULCTRL 0x28 +#define OMAP2_MCSPI_XFERLEVEL 0x7c /* per-channel banks, 0x14 bytes each, first is: */ #define OMAP2_MCSPI_CHCONF0 0x2c @@ -88,11 +90,15 @@ #define OMAP2_MCSPI_CHCONF_IS BIT(18) #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) +#define OMAP2_MCSPI_CHCONF_FFET BIT(27) +#define OMAP2_MCSPI_CHCONF_FFER BIT(28) #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) +#define OMAP2_MCSPI_IRQ_EOW BIT(17) + #define OMAP2_MCSPI_CHCTRL_EN BIT(0) #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) @@ -128,6 +134,10 @@ struct omap2_mcspi { unsigned long phys; /* SPI1 has 4 channels, while SPI2 has 2 */ struct omap2_mcspi_dma *dma_channels; + u8 mcspi_mode; + u8 dma_mode; + u8 force_cs_mode; + u16 fifo_depth; }; struct omap2_mcspi_cs { @@ -151,6 +161,37 @@ struct omap2_mcspi_regs { static struct omap2_mcspi_regs omap2_mcspi_ctx[OMAP2_MCSPI_MAX_CTRL]; +#ifdef CONFIG_SPI_DEBUG +struct reg_type { + char name[40]; + int offset; +}; + +static struct reg_type reg_map[] = { + {"MCSPI_REV", 0x0}, + {"MCSPI_SYSCONFIG", 0x10}, + {"MCSPI_SYSSTATUS", 0x14}, + {"MCSPI_IRQSTATUS", 0x18}, + {"MCSPI_IRQENABLE", 0x1C}, + {"MCSPI_WAKEUPENABLE", 0x20}, + {"MCSPI_SYST", 0x24}, + {"MCSPI_MODULCTRL", 0x28}, + {"MCSPI_XFERLEVEL", 0x7c}, + {"CH0", 0x2C}, + {"CH1", 0x40}, + {"CH2", 0x54}, + {"CH3", 0x68} +}; + +static struct reg_type ch_reg_type[] = { + {"CONF", 0x00}, + {"STAT", 0x04}, + {"CTRL", 0x08}, + {"TX", 0x0C}, + {"RX", 0x10}, +}; +#endif + static struct workqueue_struct *omap2_mcspi_wq; #define MOD_REG_BIT(val, mask, set) do { \ @@ -221,6 +262,39 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi, mcspi_write_chconf0(spi, l); } +#ifdef CONFIG_SPI_DEBUG +static int +omap2_mcspi_dump_regs(struct spi_master *master) +{ + u32 spi_base; + u32 reg; + u32 channel; + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + + spi_base = (u32)mcspi->base; + + for (reg = 0; (reg < ARRAY_SIZE(reg_map)); reg++) { + struct reg_type *reg_d = ®_map[reg]; + u32 base1 = spi_base + reg_d->offset; + if (reg_d->name[0] == 'C') { + for (channel = 0; (channel < (ARRAY_SIZE(ch_reg_type))); + channel++) { + struct reg_type *reg_c = &ch_reg_type[channel]; + u32 base2 = base1 + reg_c->offset; + pr_debug("MCSPI_%s%s [0x%08X] = 0x%08X\n", + reg_d->name, reg_c->name, base2, + __raw_readl(base2)); + } + } else { + pr_debug("%s : [0x%08X] = 0x%08X\n", + reg_d->name, base1, __raw_readl(base1)); + } + + } + return 0; +} +#endif + static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) { u32 l; @@ -238,22 +312,135 @@ static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) mcspi_write_chconf0(spi, l); } +static int omap2_mcspi_set_txfifo(const struct spi_device *spi, int buf_size, + int enable) +{ + u32 l, rw, s; + unsigned short revert = 0; + struct spi_master *master = spi->master; + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + + l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); + s = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); + + if (enable == 1) { + + /* FIFO cannot be enabled for both TX and RX + * simultaneously + */ + if (l & OMAP2_MCSPI_CHCONF_FFER) + return -EPERM; + + /* Channel needs to be disabled and enabled + * for FIFO setting to take affect + */ + if (s & OMAP2_MCSPI_CHCTRL_EN) { + omap2_mcspi_set_enable(spi, 0); + revert = 1; + } + + if (buf_size < mcspi->fifo_depth) + mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, + ((buf_size << 16) | + (buf_size - 1) << 0)); + else + mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, + ((buf_size << 16) | + (mcspi->fifo_depth - 1) << 0)); + } + + rw = OMAP2_MCSPI_CHCONF_FFET; + MOD_REG_BIT(l, rw, enable); + mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l); + + if (revert) + omap2_mcspi_set_enable(spi, 1); + + return 0; + +} + +static int omap2_mcspi_set_rxfifo(const struct spi_device *spi, int buf_size, + int enable) +{ + u32 l, rw, s; + unsigned short revert = 0; + struct spi_master *master = spi->master; + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); + + l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); + s = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); + + if (enable == 1) { + + /* FIFO cannot be enabled for both TX and RX + * simultaneously + */ + if (l & OMAP2_MCSPI_CHCONF_FFET) + return -EPERM; + + /* Channel needs to be disabled and enabled + * for FIFO setting to take affect + */ + if (s & OMAP2_MCSPI_CHCTRL_EN) { + omap2_mcspi_set_enable(spi, 0); + revert = 1; + } + + if (buf_size < mcspi->fifo_depth) + mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, + ((buf_size << 16) | + (buf_size - 1) << 8)); + else + mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, + ((buf_size << 16) | + (mcspi->fifo_depth - 1) << 8)); + } + + rw = OMAP2_MCSPI_CHCONF_FFER; + MOD_REG_BIT(l, rw, enable); + mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l); + + if (revert) + omap2_mcspi_set_enable(spi, 1); + + return 0; + +} + static void omap2_mcspi_set_master_mode(struct spi_master *master) { u32 l; + struct omap2_mcspi *mcspi = spi_master_get_devdata(master); /* setup when switching from (reset default) slave mode - * to single-channel master mode + * to single-channel master mode based on config value */ l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0); MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0); - MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1); + + if (mcspi->force_cs_mode) + MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1); + mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); omap2_mcspi_ctx[master->bus_num - 1].modulctrl = l; } +static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(1000); + while (!(__raw_readl(reg) & bit)) { + if (time_after(jiffies, timeout)) + return -1; + cpu_relax(); + } + return 0; +} + static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) { struct spi_master *spi_cntrl; @@ -298,14 +485,17 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct