?? spi.patch
字號:
diff -Nbur linux26-cvs/arch/mips/au1000/common/clocks.c linux26-cvs.SPI/arch/mips/au1000/common/clocks.c--- linux26.cvs/arch/mips/au1000/common/clocks.c 2005-08-03 11:21:28.000000000 -0500+++ linux26.amd/arch/mips/au1000/common/clocks.c 2005-08-03 10:54:38.000000000 -0500@@ -46,7 +46,7 @@ { return au1x00_clock; }-+EXPORT_SYMBOL(get_au1x00_speed); /*diff -Nbur linux26-cvs/drivers/char/au1xxx_psc_spi.c linux26-cvs.SPI/drivers/char/au1xxx_psc_spi.c--- linux26.cvs/drivers/char/au1xxx_psc_spi.c 1969-12-31 18:00:00.000000000 -0600+++ linux26.amd/drivers/char/au1xxx_psc_spi.c 2005-08-03 10:55:08.000000000 -0500@@ -0,0 +1,552 @@+/*+ * Driver for Alchemy Au1550 SPI on the PSC.+ *+ * Copyright 2004 Embedded Edge, LLC.+ * dan@embeddededge.com+ *+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+ *+ * 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.,+ * 675 Mass Ave, Cambridge, MA 02139, USA.+ */++#include <linux/module.h>+#include <linux/config.h>+#include <linux/types.h>+#include <linux/kernel.h>+#include <linux/miscdevice.h>+#include <linux/init.h>+#include <linux/fs.h>+#include <asm/uaccess.h>+#include <asm/io.h>+#include <asm/mach-au1x00/au1000.h>+#include <asm/mach-au1x00/au1550_spi.h>+#include <asm/mach-au1x00/au1xxx_psc.h>++#ifdef CONFIG_MIPS_PB1550+#include <asm/mach-pb1x00/pb1550.h>+#endif++#ifdef CONFIG_MIPS_DB1550+#include <asm/mach-db1x00/db1x00.h>+#endif++#ifdef CONFIG_MIPS_PB1200+#include <asm/mach-pb1x00/pb1200.h>+#endif++#ifdef CONFIG_MIPS_DB1200+#include <asm/mach-db1x00/db1200.h>+#endif++#ifdef CONFIG_PM+#include <asm/mach-au1x00/au1xxx_pm.h>+#endif+++/* This is just a simple programmed I/O SPI interface on the PSC of the 1550.+ * We support open, close, write, and ioctl. The SPI is a full duplex+ * interface, you can't read without writing. So, the write system call+ * copies the bytes out to the SPI, and whatever is returned is placed+ * in the same buffer. Kinda weird, maybe we'll change it, but for now+ * it works OK.+ * I didn't implement any DMA yet, and it's a debate about the necessity.+ * The SPI clocks are usually quite fast, so data is sent/received as+ * quickly as you can stuff the FIFO. The overhead of DMA and interrupts+ * are usually far greater than the data transfer itself. If, however,+ * we find applications that move large amounts of data, we may choose+ * use the overhead of buffering and DMA to do the work.+ */++/* The maximum clock rate specified in the manual is 2mHz.+*/+#define MAX_BAUD_RATE (2 * 1000000)+#define PSC_INTCLK_RATE (32 * 1000000)++static int inuse;++/* We have to know what the user requested for the data length+ * so we know how to stuff the fifo. The FIFO is 32 bits wide,+ * and we have to load it with the bits to go in a single transfer.+ */+static uint spi_datalen;+ +#ifdef CONFIG_PM +int au1200spi_pm_callback(au1xxx_power_dev_t *dev, + au1xxx_request_t request, void *data);+au1xxx_power_dev_t *SPI_pm_dev;+#endif+++static int+au1550spi_master_done( int ms )+{+ int timeout=ms;+ volatile psc_spi_t *sp;++ sp = (volatile psc_spi_t *)SPI_PSC_BASE;++ /* Loop until MD is set or timeout has expired */+ while(!(sp->psc_spievent & PSC_SPIEVNT_MD) && timeout--) udelay(1000);++ if ( !timeout )+ return 0;+ else+ sp->psc_spievent |= PSC_SPIEVNT_MD;++ return 1;+}++static int+au1550spi_open(struct inode *inode, struct file *file)+{+ if (inuse)+ return -EBUSY;++ inuse = 1;++ + return 0;+}++static ssize_t+au1550spi_write(struct file *fp, const char *bp, size_t count, loff_t *ppos)+{+ int bytelen, i;+ size_t rcount, retval;+ unsigned char sb, *rp, *wp;+ uint fifoword, pcr, stat;+ volatile psc_spi_t *sp;++ /* Get the number of bytes per transfer.+ */+ bytelen = ((spi_datalen - 1) / 8) + 1;++ /* User needs to send us multiple of this count.+ */+ if ((count % bytelen) != 0)+ return -EINVAL;++ rp = wp = (unsigned char *)bp;+ retval = rcount = count;++ /* Reset the FIFO.+ */+ sp = (volatile psc_spi_t *)SPI_PSC_BASE;+ sp->psc_spipcr = (PSC_SPIPCR_RC | PSC_SPIPCR_TC);+ au_sync();+ do {+ pcr = sp->psc_spipcr;+ au_sync();+ } while (pcr != 0);++ /* Prime the transmit FIFO.+ */+ while (count > 0) {+ fifoword = 0;+ for (i=0; i<bytelen; i++) {+ fifoword <<= 8;+ if (get_user(sb, wp) < 0)+ return -EFAULT;+ fifoword |= sb;+ wp++;+ }+ count -= bytelen;+ if (count <= 0)+ fifoword |= PSC_SPITXRX_LC;+ sp->psc_spitxrx = fifoword;+ au_sync();+ stat = sp->psc_spistat;+ au_sync();+ if (stat & PSC_SPISTAT_TF)+ break;+ }++ /* Start the transfer.+ */+ sp->psc_spipcr = PSC_SPIPCR_MS;+ au_sync();++ /* Now, just keep the transmit fifo full and empty the receive.+ */+ while (count > 0) {+ stat = sp->psc_spistat;+ au_sync();+ while ((stat & PSC_SPISTAT_RE) == 0) {+ fifoword = sp->psc_spitxrx;+ au_sync();+ for (i=0; i<bytelen; i++) {+ sb = fifoword & 0xff;+ if (put_user(sb, rp) < 0)+ return -EFAULT;+ fifoword >>= 8;+ rp++;+ }+ rcount -= bytelen;+ stat = sp->psc_spistat;+ au_sync();+ }+ if ((stat & PSC_SPISTAT_TF) == 0) {+ fifoword = 0;+ for (i=0; i<bytelen; i++) {+ fifoword <<= 8;+ if (get_user(sb, wp) < 0)+ return -EFAULT;+ fifoword |= sb;+ wp++;+ }+ count -= bytelen;+ if (count <= 0)+ fifoword |= PSC_SPITXRX_LC;+ sp->psc_spitxrx = fifoword;+ au_sync();+ }+ }++ /* All of the bytes for transmit have been written. Hang+ * out waiting for any residual bytes that are yet to be+ * read from the fifo.+ */+ while (rcount > 0) {+ stat = sp->psc_spistat;+ au_sync();+ if ((stat & PSC_SPISTAT_RE) == 0) {+ fifoword = sp->psc_spitxrx;+ au_sync();+ for (i=0; i<bytelen; i++) {+ sb = fifoword & 0xff;+ if (put_user(sb, rp) < 0)+ return -EFAULT;+ fifoword >>= 8;+ rp++;+ }+ rcount -= bytelen;+ }+ }++ /* Wait for MasterDone event. 30ms timeout */+ if (!au1550spi_master_done(30) ) retval = -EFAULT;+ return retval;+}++static int+au1550spi_release(struct inode *inode, struct file *file)+{+ + inuse = 0;++ return 0;+}++/* Set the baud rate closest to the request, then return the actual+ * value we are using.+ */+static uint+set_baud_rate(uint baud)+{+ uint rate, tmpclk, brg, ctl, stat;+ volatile psc_spi_t *sp;++ /* For starters, the input clock is divided by two.+ */+ tmpclk = PSC_INTCLK_RATE/2;++ rate = tmpclk / baud;++ /* The dividers work as follows:+ * baud = tmpclk / (2 * (brg + 1))+ */+ brg = (rate/2) - 1;++ /* Test BRG to ensure it will fit into the 6 bits allocated.+ */++ /* Make sure the device is disabled while we make the change.+ */+ sp = (volatile psc_spi_t *)SPI_PSC_BASE;+ ctl = sp->psc_spicfg;+ au_sync();+ sp->psc_spicfg = ctl & ~PSC_SPICFG_DE_ENABLE;+ au_sync();+ ctl = PSC_SPICFG_CLR_BAUD(ctl);+ ctl |= PSC_SPICFG_SET_BAUD(brg);+ sp->psc_spicfg = ctl;+ au_sync();++ /* If the device was running prior to getting here, wait for+ * it to restart.+ */+ if (ctl & PSC_SPICFG_DE_ENABLE) {+ do {+ stat = sp->psc_spistat;+ au_sync();+ } while ((stat & PSC_SPISTAT_DR) == 0);+ }++ /* Return the actual value.+ */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -