From patchwork Wed Oct 9 14:46:03 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nikita Kiryanov X-Patchwork-Id: 281909 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 373182C00E2 for ; Thu, 10 Oct 2013 01:46:59 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1ADEA4A098; Wed, 9 Oct 2013 16:46:51 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id BR7qQfLKZulZ; Wed, 9 Oct 2013 16:46:50 +0200 (CEST) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id BA53D4A09F; Wed, 9 Oct 2013 16:46:33 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id BE1914A080 for ; Wed, 9 Oct 2013 16:46:26 +0200 (CEST) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id fmJxVbgJF1g6 for ; Wed, 9 Oct 2013 16:46:25 +0200 (CEST) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from compulab.co.il (softlayer.compulab.co.il [50.23.254.55]) by theia.denx.de (Postfix) with ESMTPS id 1EA614A088 for ; Wed, 9 Oct 2013 16:46:14 +0200 (CEST) Received: from [82.166.188.245] (port=33306 helo=zimbra-mta.compulab.co.il) by softlayer.compulab.co.il with esmtp (Exim 4.80.1) (envelope-from ) id 1VTv1g-0007My-Ue; Wed, 09 Oct 2013 17:46:13 +0300 Received: from localhost (localhost.localdomain [127.0.0.1]) by zimbra-mta.compulab.co.il (Postfix) with ESMTP id 430A5644192; Wed, 9 Oct 2013 17:46:12 +0300 (IDT) X-Virus-Scanned: amavisd-new at compulab.co.il Received: from zimbra-mta.compulab.co.il ([127.0.0.1]) by localhost (zimbra-mta.compulab.co.il [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id bpRfwSpoOrxZ; Wed, 9 Oct 2013 17:46:10 +0300 (IDT) Received: from compulab.co.il (nikita-pc.compulab.local [192.168.11.211]) by zimbra-mta.compulab.co.il (Postfix) with ESMTP id CD2AE64419C; Wed, 9 Oct 2013 17:46:09 +0300 (IDT) Received: by compulab.co.il (Postfix, from userid 1000) id 6F69AFC2E96; Wed, 9 Oct 2013 17:46:09 +0300 (IDT) From: Nikita Kiryanov To: u-boot@lists.denx.de Date: Wed, 9 Oct 2013 17:46:03 +0300 Message-Id: <1381329965-7775-2-git-send-email-nikita@compulab.co.il> X-Mailer: git-send-email 1.8.1.2 In-Reply-To: <1381329965-7775-1-git-send-email-nikita@compulab.co.il> References: <1381329965-7775-1-git-send-email-nikita@compulab.co.il> X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - softlayer.compulab.co.il X-AntiAbuse: Original Domain - lists.denx.de X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - compulab.co.il X-Get-Message-Sender-Via: softlayer.compulab.co.il: acl_c_relayhosts_text_entry: nikita@compulab.co.il|compulab.co.il Cc: Tom Rini Subject: [U-Boot] [PATCH 1/3] spi: omap3: add support for more word lengths X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Current implementation only supports 8 bit word lengths, even though omap3 can handle anything between 4 and 32. Update the spi interface to support changing the SPI word length, and implement it in omap3_spi driver to support the full range of possible word lengths. This implementation is backwards compatible by defaulting to the old behavior of 8 bit word lengths. Also, it required a change to the omap3_spi non static I/O functions, but since they are not used anywhere else, no collateral changes are required. Cc: Tom Rini Cc: Igor Grinberg Cc: Jagannadha Sutradharudu Teki Signed-off-by: Nikita Kiryanov --- drivers/spi/omap3_spi.c | 78 ++++++++++++++++++++++++++++++++++++++----------- drivers/spi/omap3_spi.h | 11 ++++--- include/spi.h | 13 +++++++++ 3 files changed, 81 insertions(+), 21 deletions(-) diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c index 6bac245..add98e1 100644 --- a/drivers/spi/omap3_spi.c +++ b/drivers/spi/omap3_spi.c @@ -20,7 +20,7 @@ #include #include "omap3_spi.h" -#define WORD_LEN 8 +#define SPI_DEFAULT_WORDLEN 8; #define SPI_WAIT_TIMEOUT 3000000; static void spi_reset(struct omap3_spi_slave *ds) @@ -128,10 +128,32 @@ struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, ds->regs = regs; ds->freq = max_hz; ds->mode = mode; + ds->wordlen = SPI_DEFAULT_WORDLEN; return &ds->slave; } +int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen) +{ + struct omap3_spi_slave *ds; + int chconf; + + if (wordlen < 4 || wordlen > 32) { + printf("SPI error: unsupported wordlen %d\n", wordlen); + return -1; + } + + ds = to_omap3_spi(slave); + ds->wordlen = wordlen; + + chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); + chconf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; + chconf |= (wordlen - 1) << 7; + omap3_spi_write_chconf(ds, chconf); + + return 0; +} + void spi_free_slave(struct spi_slave *slave) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -185,7 +207,7 @@ int spi_claim_bus(struct spi_slave *slave) /* wordlength */ conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK; - conf |= (WORD_LEN - 1) << 7; + conf |= (ds->wordlen - 1) << 7; /* set chipselect polarity; manage with FORCE */ if (!(ds->mode & SPI_CS_HIGH)) @@ -223,7 +245,7 @@ void spi_release_bus(struct spi_slave *slave) spi_reset(ds); } -int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -250,7 +272,13 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, } } /* Write the data */ - writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); + unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; + if (ds->wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->wordlen > 8) + writel(((u16 *)txp)[i], tx); + else + writel(((u8 *)txp)[i], tx); } /* wait to finish of transfer */ @@ -268,7 +296,7 @@ int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, return 0; } -int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); @@ -302,7 +330,13 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); /* Read the data */ - rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); + unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; + if (ds->wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->wordlen > 8) + ((u16 *)rxp)[i] = (u16)readl(rx); + else + ((u8 *)rxp)[i] = (u8)readl(rx); } if (flags & SPI_XFER_END) { @@ -314,8 +348,8 @@ int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, } /*McSPI Transmit Receive Mode*/ -int omap3_spi_txrx(struct spi_slave *slave, - unsigned int len, const u8 *txp, u8 *rxp, unsigned long flags) +int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, + const void *txp, void *rxp, unsigned long flags) { struct omap3_spi_slave *ds = to_omap3_spi(slave); int timeout = SPI_WAIT_TIMEOUT; @@ -344,7 +378,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Write the data */ - writel(txp[i], &ds->regs->channel[ds->slave.cs].tx); + unsigned int *tx = &ds->regs->channel[ds->slave.cs].tx; + if (ds->wordlen > 16) + writel(((u32 *)txp)[i], tx); + else if (ds->wordlen > 8) + writel(((u16 *)txp)[i], tx); + else + writel(((u8 *)txp)[i], tx); /*Read: wait for RX containing data (RXS == 1)*/ while (!(readl(&ds->regs->channel[ds->slave.cs].chstat) & @@ -356,7 +396,13 @@ int omap3_spi_txrx(struct spi_slave *slave, } } /* Read the data */ - rxp[i] = readl(&ds->regs->channel[ds->slave.cs].rx); + unsigned int *rx = &ds->regs->channel[ds->slave.cs].rx; + if (ds->wordlen > 16) + ((u32 *)rxp)[i] = readl(rx); + else if (ds->wordlen > 8) + ((u16 *)rxp)[i] = (u16)readl(rx); + else + ((u8 *)rxp)[i] = (u8)readl(rx); } /* Disable the channel */ omap3_spi_set_enable(ds,OMAP3_MCSPI_CHCTRL_DIS); @@ -375,14 +421,12 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, { struct omap3_spi_slave *ds = to_omap3_spi(slave); unsigned int len; - const u8 *txp = dout; - u8 *rxp = din; int ret = -1; - if (bitlen % 8) + if (bitlen % ds->wordlen) return -1; - len = bitlen / 8; + len = bitlen / ds->wordlen; if (bitlen == 0) { /* only change CS */ int chconf = readl(&ds->regs->channel[ds->slave.cs].chconf); @@ -400,11 +444,11 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, ret = 0; } else { if (dout != NULL && din != NULL) - ret = omap3_spi_txrx(slave, len, txp, rxp, flags); + ret = omap3_spi_txrx(slave, len, dout, din, flags); else if (dout != NULL) - ret = omap3_spi_write(slave, len, txp, flags); + ret = omap3_spi_write(slave, len, dout, flags); else if (din != NULL) - ret = omap3_spi_read(slave, len, rxp, flags); + ret = omap3_spi_read(slave, len, din, flags); } return ret; } diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h index 01537b6..aeddb53 100644 --- a/drivers/spi/omap3_spi.h +++ b/drivers/spi/omap3_spi.h @@ -92,6 +92,7 @@ struct omap3_spi_slave { struct mcspi *regs; unsigned int freq; unsigned int mode; + unsigned int wordlen; }; static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) @@ -99,11 +100,13 @@ static inline struct omap3_spi_slave *to_omap3_spi(struct spi_slave *slave) return container_of(slave, struct omap3_spi_slave, slave); } -int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const u8 *txp, - u8 *rxp, unsigned long flags); -int omap3_spi_write(struct spi_slave *slave, unsigned int len, const u8 *txp, +int omap3_spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen); + +int omap3_spi_txrx(struct spi_slave *slave, unsigned int len, const void *txp, + void *rxp, unsigned long flags); +int omap3_spi_write(struct spi_slave *slave, unsigned int len, const void *txp, unsigned long flags); -int omap3_spi_read(struct spi_slave *slave, unsigned int len, u8 *rxp, +int omap3_spi_read(struct spi_slave *slave, unsigned int len, void *rxp, unsigned long flags); #endif /* _OMAP3_SPI_H_ */ diff --git a/include/spi.h b/include/spi.h index c0dab57..ae318ff 100644 --- a/include/spi.h +++ b/include/spi.h @@ -149,6 +149,19 @@ int spi_claim_bus(struct spi_slave *slave); void spi_release_bus(struct spi_slave *slave); /*----------------------------------------------------------------------- + * Set the word length for SPI transactions + * + * Set the word length (number of bits per word) for SPI transactions. + * This setting is persistent until changed. + * + * slave: The SPI slave + * wordlen: The number of bits in a word + * + * Returns: 0 on success, -1 on failure. + */ +int spi_set_wordlen(struct spi_slave *slave, unsigned int wordlen); + +/*----------------------------------------------------------------------- * SPI transfer * * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks