📄 spi.patch
字号:
+ rate = tmpclk / (2 * (brg + 1));++ return(rate);+}++static uint+set_word_len(uint len)+{+ uint ctl, stat;+ volatile psc_spi_t *sp;++ if ((len < 4) || (len > 24))+ return -EINVAL;++ /* 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_LEN(ctl);+ ctl |= PSC_SPICFG_SET_LEN(len);+ 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 0;+}++static uint+set_clk_src(void)+{+ uint clk, rate;++/* Wire up Freq3 as a clock for the SPI. The PSC does+ * factor of 2 divisor, so run a higher rate so we can+ * get some granularity to the clock speeds.+ * We can't do this in board set up because the frequency+ * is computed too late.+ */+ rate = get_au1x00_speed();+ rate /= PSC_INTCLK_RATE;+ ++ + /* The FRDIV in the frequency control is (FRDIV + 1) * 2+ */+ rate /=2;+ rate--;+ clk = au_readl(SYS_FREQCTRL1);+ + au_sync();+ clk &= ~SYS_FC_FRDIV3_MASK;+ clk |= (rate << SYS_FC_FRDIV3_BIT);+ clk |= SYS_FC_FE3;+ au_writel(clk, SYS_FREQCTRL1);+ au_sync();++ /* Set up the clock source routing to get Freq3 to PSC0_intclk.+ */+ clk = au_readl(SYS_CLKSRC);+ au_sync();+#if defined(CONFIG_SOC_AU1200)+ clk &= ~SYS_CS_ME0_MASK;+ clk |= (5 << 22);+#elif defined (CONFIG_SOC_AU1550)+ clk &= ~0x03e0;+ clk |= (5 << 7);+#endif+ au_writel(clk, SYS_CLKSRC);+ au_sync();++ /* Set up GPIO pin function to drive PSC0_SYNC1, which is+ * the SPI Select.+ */+ clk = au_readl(SYS_PINFUNC);+ au_sync();+#if defined(CONFIG_SOC_AU1200)+ clk |= (0x1 <<17);+ clk &= ~SYS_PINFUNC_P0B;+#elif defined (CONFIG_SOC_AU1550)+ clk |= 1;+#endif+ au_writel(clk, SYS_PINFUNC);+ au_sync();++ return 0;+} ++static int+au1550spi_ioctl(struct inode *inode, struct file *file,+ unsigned int cmd, unsigned long arg)+{+ int status;+ u32 val;++ status = 0;++ switch(cmd) {+ case AU1550SPI_WORD_LEN:+ status = set_word_len(arg);+ break;++ case AU1550SPI_SET_BAUD:+ if (get_user(val, (u32 *)arg)) + return -EFAULT;++ val = set_baud_rate(val);+ if (put_user(val, (u32 *)arg)) + return -EFAULT;+ break;++ default:+ status = -ENOIOCTLCMD;++ }++ return status;+}++static struct file_operations au1550spi_fops =+{ .owner = THIS_MODULE,+ .write = au1550spi_write,+ .ioctl = au1550spi_ioctl,+ .open = au1550spi_open,+ .release = au1550spi_release,+};+++static struct miscdevice au1550spi_miscdev =+{+ .minor = MISC_DYNAMIC_MINOR,+ .name = "au1550_spi",+ .fops = &au1550spi_fops,+};+++#ifdef CONFIG_PM++int au1200spi_pm_callback(au1xxx_power_dev_t *dev, + au1xxx_request_t request, void *data) {+ + int retval = -1;+ + if (request == AU1XXX_PM_SLEEP) {+ /* DO Nothing for time being*/+ }+ else if (request == AU1XXX_PM_WAKEUP) {+ /* Set Clock Again*/+ + set_clk_src();+ + }+ else if (request == AU1XXX_PM_GETSTATUS) {+ return dev->cur_state;+ }+ else if (request == AU1XXX_PM_ACCESS) {+ if (dev->cur_state != SLEEP_STATE)+ return retval;+ else {+ //au1200_setpanel(panel);+ }+ }+ else if (request == AU1XXX_PM_IDLE) {+ }+ else if (request == AU1XXX_PM_CLEANUP) {+ }++ return retval; +}+#endif++++int __init+au1550spi_init(void)+{+ uint stat;+ volatile psc_spi_t *sp;+ + /* Set clock Source*/+ set_clk_src();++ /* Now, set up the PSC for SPI PIO mode.+ */+ sp = (volatile psc_spi_t *)SPI_PSC_BASE;+ sp->psc_ctrl = PSC_CTRL_DISABLE;+ au_sync();+ sp->psc_sel = PSC_SEL_PS_SPIMODE;+ sp->psc_spicfg = 0;+ au_sync();+ sp->psc_ctrl = PSC_CTRL_ENABLE;+ au_sync();+ + do {+ stat = sp->psc_spistat;+ au_sync();+ } while ((stat & PSC_SPISTAT_SR) == 0);+ + + sp->psc_spicfg = (PSC_SPICFG_RT_FIFO8 | PSC_SPICFG_TT_FIFO8 |+ PSC_SPICFG_DD_DISABLE | PSC_SPICFG_MO);+ sp->psc_spicfg |= PSC_SPICFG_SET_LEN(8); + spi_datalen = 8;+ sp->psc_spimsk = PSC_SPIMSK_ALLMASK;+ au_sync();++ set_baud_rate(1000000);++ sp->psc_spicfg |= PSC_SPICFG_DE_ENABLE;+ + do {+ stat = sp->psc_spistat;+ au_sync();+ } while ((stat & PSC_SPISTAT_DR) == 0);+++ misc_register(&au1550spi_miscdev);+#ifdef CONFIG_PM+ SPI_pm_dev = new_au1xxx_power_device("SPI", &au1200spi_pm_callback, NULL);+ if ( SPI_pm_dev == NULL)+ printk(KERN_INFO "Unable to create a power management device entry for the au1200-SPI.\n");+ else+ printk(KERN_INFO "Power management device entry for the au1200-SPI loaded.\n");+#endif++ printk("Au1550/Au1200 SPI driver\n");+ return 0;+} +++void __exit+au1550spi_exit(void)+{+ misc_deregister(&au1550spi_miscdev);+}+++module_init(au1550spi_init);+module_exit(au1550spi_exit);diff -Nbur linux26-cvs/drivers/char/Kconfig linux26-cvs.SPI/drivers/char/Kconfig--- linux26.cvs/drivers/char/Kconfig 2005-08-03 11:23:00.000000000 -0500+++ linux26.amd/drivers/char/Kconfig 2005-08-03 10:54:38.000000000 -0500@@ -369,6 +369,10 @@ tristate "Au1200 Camera Interface Module (CIM)" depends on MIPS && SOC_AU1X00 +config AU1XXX_PSC_SPI+ tristate ' Alchemy Au1550/Au1200 PSC SPI support'+ depends on MIPS && SOC_AU1X00+ config SERIAL_TX3912diff -Nbur linux26-cvs/drivers/char/Makefile linux26-cvs.SPI/drivers/char/Makefile--- linux26.cvs/drivers/char/Makefile 2005-08-03 11:23:00.000000000 -0500+++ linux26.amd/drivers/char/Makefile 2005-08-03 10:54:38.000000000 -0500@@ -84,6 +84,7 @@ obj-$(CONFIG_AU1000_USB_TTY) += au1000_usbtty.o obj-$(CONFIG_AU1000_USB_RAW) += au1000_usbraw.o obj-$(CONFIG_AU1XXX_CIM) += au1xxx_cim.o+obj-$(CONFIG_AU1XXX_PSC_SPI) += au1xxx_psc_spi.o obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.odiff -Nbur linux26-cvs/include/asm-mips/mach-au1x00/au1550_spi.h linux26-cvs.SPI/include/asm-mips/mach-au1x00/au1550_spi.h--- linux26.cvs/include/asm-mips/mach-au1x00/au1550_spi.h 1969-12-31 18:00:00.000000000 -0600+++ linux26.amd/include/asm-mips/mach-au1x00/au1550_spi.h 2005-08-03 10:54:38.000000000 -0500@@ -0,0 +1,38 @@+/*+ * API to Alchemy Au1550 SPI device.+ *+ * 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.+ */++#ifndef __AU1550_SPI_H+#define __AU1550_SPI_H++#include <linux/ioctl.h>++#define AU1550SPI_IOC_MAGIC 'S'++#define AU1550SPI_SET_BAUD _IOW(AU1550SPI_IOC_MAGIC, 0, int *)+#define AU1550SPI_WORD_LEN _IOW(AU1550SPI_IOC_MAGIC, 1, int)++#endif /* __AU1000_SPI_H */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -