diff options
Diffstat (limited to 'packages/linux/linux-rp-2.6.21/locomo_spi-r4.patch')
-rw-r--r-- | packages/linux/linux-rp-2.6.21/locomo_spi-r4.patch | 947 |
1 files changed, 947 insertions, 0 deletions
diff --git a/packages/linux/linux-rp-2.6.21/locomo_spi-r4.patch b/packages/linux/linux-rp-2.6.21/locomo_spi-r4.patch new file mode 100644 index 0000000000..7ecc48f956 --- /dev/null +++ b/packages/linux/linux-rp-2.6.21/locomo_spi-r4.patch @@ -0,0 +1,947 @@ +Index: linux-2.6.21/drivers/spi/Kconfig +=================================================================== +--- linux-2.6.21.orig/drivers/spi/Kconfig 2007-04-26 05:08:32.000000000 +0200 ++++ linux-2.6.21/drivers/spi/Kconfig 2007-07-03 21:40:52.000000000 +0200 +@@ -89,6 +89,10 @@ + This enables using the Freescale iMX SPI controller in master + mode. + ++config SPI_LOCOMO ++ tristate "Locomo SPI master" ++ depends on SPI_MASTER && SHARP_LOCOMO && EXPERIMENTAL ++ + config SPI_MPC83xx + tristate "Freescale MPC83xx SPI controller" + depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL +Index: linux-2.6.21/drivers/spi/locomo_spi.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/spi/locomo_spi.c 2007-07-03 21:40:52.000000000 +0200 +@@ -0,0 +1,873 @@ ++#include <asm/io.h> ++#include <asm/irq.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/device.h> ++#include <linux/stat.h> ++#include <linux/delay.h> ++#include <linux/interrupt.h> ++#include <asm/hardware/locomo.h> ++#include <linux/mmc/host.h> ++#include <linux/spi/spi.h> ++#include <linux/spi/mmc_spi.h> ++#include <linux/workqueue.h> ++#include <linux/spinlock.h> ++#include <linux/list.h> ++#include "locomo_spi.h" ++static struct locomospi_dev * spidev; ++static struct work_struct transfer_wq; ++int verbose=0; ++/* MMC_SPI functions *********************************************************/ ++ ++static int locomommcspi_init(struct device *dev, irqreturn_t (*isr)(int, void*), void *mmc) ++{ ++ int result; ++ locomo_gpio_set_irq(spidev->ldev->dev.parent, LOCOMO_GPIO_CARD_DETECT, LOCOMO_GPIO_IRQ_ON_RISE | LOCOMO_GPIO_IRQ_ON_FALL); ++ spidev->mmc_spi_isr = isr; ++ result=request_irq(IRQ_LOCOMO_CARDDETECT, locomospi_cardisr, SA_SHIRQ, "locomo-spi", mmc); ++ return result; ++} ++ ++static void locomommcspi_exit(struct device *dev, void* mmc) ++{ ++ free_irq(IRQ_LOCOMO_CARDDETECT, mmc); ++} ++ ++static int locomommcspi_getro(struct device *dev) ++{ ++ return locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_WRITE_PROTECT) > 0 ? 1 : 0; ++} ++ ++static void locomommcspi_powermode(struct device *dev, unsigned char mode) ++{ ++ if(mode == MMC_POWER_OFF && spidev->card_power != 0) ++ locomospi_power(0); ++ else if( spidev->card_power != 1) ++ locomospi_power(1); ++ ++} ++ ++static void locomommcspi_reset(void) ++{ ++ /* transmit card reset sequence, should be done from mmc_layer */ ++ locomospi_setcs(1); ++ tx("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",10); ++ locomospi_setcs(0); ++} ++ ++ ++static struct mmc_spi_platform_data colliemmc ={ ++ .init = locomommcspi_init, ++ .exit = locomommcspi_exit, ++ .detect_delay = HZ, ++ .get_ro = locomommcspi_getro, ++ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, ++ .setpowermode = locomommcspi_powermode, ++ .reset = locomommcspi_reset, ++}; ++ ++/* Utility function **********************************************************/ ++ ++static irqreturn_t locomospi_cardisr(int irq, void *dev_id) ++{ ++ u16 r; ++ if(locomospi_carddetect()){ ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r |= 0x80; ++ locomo_writel( r, spidev->base+LOCOMO_SPIMD); ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r |= 0x40; ++ locomo_writel( r, spidev->base+LOCOMO_SPIMD); ++ /* transmit card reset sequence, should be done from mmc_layer */ ++// locomospi_setcs(1); ++ // tx("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",10); ++// locomospi_setcs(0); ++ } else { ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r &= ~0x80; ++ locomo_writel( r, spidev->base+LOCOMO_SPIMD); ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r &= ~0x40; ++ locomo_writel( r, spidev->base+LOCOMO_SPIMD); ++ } ++ return spidev->mmc_spi_isr(irq, dev_id); ++} ++ ++static void locomospi_power(int on) ++{ ++ locomo_gpio_write(spidev->ldev->dev.parent, LOCOMO_GPIO_CARD_POWER, on); ++ spidev->card_power=on; ++ set_current_state(TASK_INTERRUPTIBLE); ++ if(on){ ++ schedule_timeout(HZ/10); ++ } else { ++ schedule_timeout(2*HZ); ++ } ++ ++} ++ ++static void locomospi_setclock(unsigned int base, unsigned int mult) ++{ ++ u16 r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ base &= 0x7; ++ mult &= 0x3; ++ r &= ~(0x7 | 0x18 | 0x40); ++ locomo_writel(r,spidev->base+LOCOMO_SPIMD); ++ r |= (base | (mult <<3) | 0x40); ++ locomo_writel(r,spidev->base+LOCOMO_SPIMD); ++ spidev->clock_base = base; ++ spidev->clock_mult = mult; ++ ++} ++// returns 1 if card ist present, 0 otherwise ++static int locomospi_carddetect() ++{ ++ return (locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_CARD_DETECT)>0)?0:1; ++} ++ ++static void locomospi_togglecs() ++{ ++ u16 r; ++ r = locomo_readl(spidev->base + LOCOMO_SPICT); ++ r ^= 0x40; // I think this is CHIPSELECTHIGH ++ locomo_writel(r, spidev->base + LOCOMO_SPICT); ++} ++ ++static void locomospi_setcs(int high) ++{ ++ u16 r; ++ r = locomo_readl(spidev->base + LOCOMO_SPICT); ++ if(high) ++ r |= 0x40; ++ else ++ r &= ~0x40; ++ locomo_writel(r, spidev->base + LOCOMO_SPICT); ++} ++ ++static void locomospi_reg_open() ++{ ++ u16 r; ++ spidev->clock_base = 4; ++ spidev->clock_mult = 0; ++ locomospi_power(1); ++ locomo_writel( 0x6c00 | (2 <<3)|4, spidev->base+LOCOMO_SPIMD); ++ if(locomospi_carddetect()){ ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r |= 0x80; ++ locomo_writel( r, spidev->base+LOCOMO_SPIMD); ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r |= 0x40; ++ locomo_writel( r, spidev->base+LOCOMO_SPIMD); ++ } ++ locomo_writel( 0x40, spidev->base+LOCOMO_SPICT); ++ r = locomo_readl(spidev->base+LOCOMO_SPICT); ++ r |= 0x80; ++ locomo_writel( r, spidev->base+LOCOMO_SPICT); ++ udelay(200); ++ r = locomo_readl(spidev->base+LOCOMO_SPICT); ++ locomo_writel(r, spidev->base+LOCOMO_SPICT); ++ r = locomo_readl(spidev->base+LOCOMO_SPICT); ++ r |= 0x1; ++ locomo_writel(r, spidev->base+LOCOMO_SPICT); ++ r = locomo_readl(spidev->base+LOCOMO_SPICT); ++ r &= ~0x40; ++ locomo_writel(r, spidev->base+LOCOMO_SPICT); ++} ++ ++static void locomospi_reg_release() ++{ ++ u16 r; ++ r = locomo_readl(spidev->base+LOCOMO_SPICT); ++ r &= ~0x80; ++ locomo_writel(r, spidev->base+LOCOMO_SPICT); ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r &= ~0x40; ++ locomo_writel(r, spidev->base+LOCOMO_SPIMD); ++ r = locomo_readl(spidev->base+LOCOMO_SPIMD); ++ r &= ~0x80; ++ locomo_writel(r, spidev->base+LOCOMO_SPIMD); ++ r = locomo_readl(spidev->base+LOCOMO_SPICT); ++ r |= 0x40; ++ locomo_writel(r, spidev->base+LOCOMO_SPICT); ++ locomospi_power(0); ++} ++ ++static int tx(const char* buffer, int size) ++{ ++ int i=0,j=0; ++// int result=0; ++ int wait; ++ if(!spidev->clock_base && !spidev->clock_mult) ++ return 0; ++ if(spidev->clock_base == 4) ++ wait = 0x10000; ++ else ++ wait = 8; ++ ++ for(i=0; i<size; i++){ ++/* if(!(locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW)){ ++ result = wait_event_interruptible(spidev->waitqueue, locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW); ++ if(result) { ++ dev_err(&spidev->sdev->dev, "received Signal. giving up tx."); ++ return i; ++ } ++ }*/ ++ for(j=0; j <= wait; j++){ ++ if(locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW) ++ break; ++ } ++ locomo_writel((u16) buffer[i], spidev->base+LOCOMO_SPITD); ++ if(verbose) ++ printk(KERN_DEBUG "locomospi: sent: char :%x\n", (u16) buffer[i]); ++ if(spidev->clock_base){ ++ for(j=0; j <= wait; j++){ ++ if(!(locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW)) ++ break; ++ } ++ } ++ } ++ if(spidev->clock_base){ ++ for(i=0; i <= wait; i++){ ++ if(locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_TEND) ++ break; ++ } ++ } ++ return j; ++} ++ ++static int rx(char* buffer, int size) ++{ ++ int i,j; ++// int result=0; ++ int wait; ++ u16 rd; ++ if(!spidev->clock_base && !spidev->clock_mult) ++ return 0; ++ if(spidev->clock_base == 4) ++ wait = 0x10000; ++ else ++ wait = 8; ++ ++ for(i=0; i<size; i++){ ++/* if(!(locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW)){ ++ result = wait_event_interruptible(spidev->waitqueue, locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW); ++ if(result) { ++ dev_err(&spidev->sdev->dev, "received Signal. giving up tx."); ++ return i; ++ } ++ }*/ ++ for(j=0; j <= wait; j++){ ++ if(locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFR) ++ break; ++ } ++ rd= locomo_readl(spidev->base+LOCOMO_SPIRD); ++ if(verbose) ++ printk(KERN_DEBUG "locomospi: received: char :%x\n", (u16) buffer[i]); ++ buffer[i]=(char) rd; ++ if(spidev->clock_base){ ++ for(j=0; j <= wait; j++){ ++ if(!(locomo_readl(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFR)) ++ break; ++ } ++ } ++ } ++ return i; ++} ++ ++/* ++static irqreturn_t locomospi_rwready(int irq, void *dev_id) ++{ ++ struct locomospi_dev* dev=(struct locomospi_dev*) dev_id; ++// dev_dbg(&spidev->sdev->dev, "IRQ: %d\n", irq); ++// printk(KERN_DEBUG "locomospi: IRQ: %d\n", irq); ++ wake_up_interruptible(&dev->waitqueue); ++ return IRQ_HANDLED; ++} ++ ++static irqreturn_t locomospi_testisr(int irq, void *dev_id) ++{ ++ char *buf=""; ++ switch(irq){ ++ case IRQ_LOCOMO_SPI_RFR: buf="RFR"; ++ break; ++ case IRQ_LOCOMO_SPI_RFW: buf="RFW"; ++ break; ++ case IRQ_LOCOMO_SPI_OVRN:buf="OVRN"; ++ break; ++ case IRQ_LOCOMO_SPI_TEND:buf="TEND"; ++ break; ++ case IRQ_LOCOMO_CARDDETECT: ++ buf="CARD_DETECT"; ++ break; ++ default: return IRQ_NONE; ++ } ++ printk(KERN_DEBUG "locomospi: IRQ: %s\n",buf); ++// dev_dbg(&spidev->sdev->dev, "IRQ: %s\n",buf); ++ return IRQ_HANDLED; ++} ++*/ ++/* sysfs attributes used for debug *******************************************/ ++ ++/* SPI registers */ ++ssize_t locomospi_showspimd(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIMD)); ++} ++ ++ssize_t locomospi_storespimd(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIMD); ++ return count; ++} ++static DRIVER_ATTR(spimd, S_IWUSR | S_IRUGO, locomospi_showspimd, locomospi_storespimd); ++ ++ssize_t locomospi_showspict(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPICT)); ++} ++ ++ssize_t locomospi_storespict(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPICT); ++ return count; ++} ++static DRIVER_ATTR(spict, S_IWUSR | S_IRUGO, locomospi_showspict, locomospi_storespict); ++ ++ssize_t locomospi_showspist(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIST)); ++} ++ ++ssize_t locomospi_storespist(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIST); ++ return count; ++} ++static DRIVER_ATTR(spist, S_IWUSR | S_IRUGO, locomospi_showspist, locomospi_storespist); ++ ++ssize_t locomospi_showspiis(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIIS)); ++} ++ ++ssize_t locomospi_storespiis(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIIS); ++ return count; ++} ++static DRIVER_ATTR(spiis, S_IWUSR | S_IRUGO, locomospi_showspiis, locomospi_storespiis); ++ ++ssize_t locomospi_showspiwe(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIWE)); ++} ++ ++ssize_t locomospi_storespiwe(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIWE); ++ return count; ++} ++static DRIVER_ATTR(spiwe, S_IWUSR | S_IRUGO, locomospi_showspiwe, locomospi_storespiwe); ++ ++ssize_t locomospi_showspiie(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIIE)); ++} ++ ++ssize_t locomospi_storespiie(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIIE); ++ return count; ++} ++static DRIVER_ATTR(spiie, S_IWUSR | S_IRUGO, locomospi_showspiie, locomospi_storespiie); ++ ++ssize_t locomospi_showspiir(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIIR)); ++} ++ ++ssize_t locomospi_storespiir(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIIR); ++ return count; ++} ++static DRIVER_ATTR(spiir, S_IWUSR | S_IRUGO, locomospi_showspiir, locomospi_storespiir); ++ ++ssize_t locomospi_showspitd(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPITD)); ++} ++ ++ssize_t locomospi_storespitd(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPITD); ++ return count; ++} ++static DRIVER_ATTR(spitd, S_IWUSR | S_IRUGO, locomospi_showspitd, locomospi_storespitd); ++ ++ssize_t locomospi_showspird(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIRD)); ++} ++ ++ssize_t locomospi_storespird(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIRD); ++ return count; ++} ++static DRIVER_ATTR(spird, S_IWUSR | S_IRUGO, locomospi_showspird, locomospi_storespird); ++ ++ssize_t locomospi_showspits(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPITS)); ++} ++ ++ssize_t locomospi_storespits(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPITS); ++ return count; ++} ++static DRIVER_ATTR(spits, S_IWUSR | S_IRUGO, locomospi_showspits, locomospi_storespits); ++ ++ssize_t locomospi_showspirs(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "0x%x\n", locomo_readl(spidev->base+LOCOMO_SPIRS)); ++} ++ ++ssize_t locomospi_storespirs(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomo_writel(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIRS); ++ return count; ++} ++static DRIVER_ATTR(spirs, S_IWUSR | S_IRUGO, locomospi_showspirs, locomospi_storespirs); ++ ++/* MMC Card status */ ++ ++ssize_t locomospi_showpower(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n", spidev->card_power); ++} ++ ++ssize_t locomospi_storepower(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomospi_power(simple_strtoul(buf, NULL, 10)); ++ return count; ++} ++static DRIVER_ATTR(cardpower, S_IWUSR | S_IRUGO, locomospi_showpower, locomospi_storepower); ++ ++ssize_t locomospi_detectcard(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n",(locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_CARD_DETECT)>0)?0:1); ++} ++static DRIVER_ATTR(carddetect, S_IRUGO, locomospi_detectcard, NULL); ++ ++ssize_t locomospi_writeprotect(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n",(locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_WRITE_PROTECT)>0)?1:0); ++} ++static DRIVER_ATTR(cardwriteprotect, S_IRUGO, locomospi_writeprotect, NULL); ++ ++ssize_t locomospi_showclockbase(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n", spidev->clock_base); ++} ++ ++ssize_t locomospi_storeclockbase(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomospi_setclock(simple_strtoul(buf, NULL, 10), spidev->clock_mult); ++ return count; ++} ++static DRIVER_ATTR(clockbase, S_IWUSR | S_IRUGO, locomospi_showclockbase, locomospi_storeclockbase); ++ ++ssize_t locomospi_showclockmult(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n", spidev->clock_mult); ++} ++ ++ssize_t locomospi_storeclockmult(struct device_driver *drv, const char *buf, size_t count) ++{ ++ locomospi_setclock(spidev->clock_base, simple_strtoul(buf, NULL, 10)); ++ return count; ++} ++static DRIVER_ATTR(clockmult, S_IWUSR | S_IRUGO, locomospi_showclockmult, locomospi_storeclockmult); ++ ++/* debug */ ++ ++ssize_t locomospi_reset(struct device_driver *drv, const char *buf, size_t count) ++{ ++ int choice = simple_strtoul(buf, NULL, 10); ++// char buff[10]; ++ switch(choice){ ++ case 0: locomospi_reg_release(); ++ locomospi_reg_open(); ++ break; ++ case 1: tx("\x40\x00\x00\x00\x00\x95",6); ++ break; ++ case 2: locomospi_setcs(1); ++ tx("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",10); ++ locomospi_setcs(0); ++ break; ++ default: /* do nothing */; ++ } ++ return count; ++} ++static DRIVER_ATTR(reset, S_IWUSR, NULL, locomospi_reset); ++ ++ssize_t locomospi_showverbose(struct device_driver *drv, char *buf) ++{ ++ return sprintf(buf, "%d\n", verbose); ++} ++ ++ssize_t locomospi_storeverbose(struct device_driver *drv, const char *buf, size_t count) ++{ ++ verbose=simple_strtoul(buf, NULL, 10); ++ return count; ++} ++static DRIVER_ATTR(verbose, S_IWUSR | S_IRUGO, locomospi_showverbose, locomospi_storeverbose); ++ ++/* SPI functions *************************************************************/ ++ ++static void locomospi_do_transfer(struct work_struct *wrk) ++{ ++ struct list_head *mptr, *tptr, *mptr2; ++ struct spi_transfer *entry; ++ struct spi_message *msg; ++ ++ list_for_each_safe(mptr, mptr2, &spidev->message_list){ ++ int i; ++ msg = list_entry(mptr, struct spi_message, queue); ++ ++ msg->status = 0; ++ msg->actual_length = 0; ++ list_for_each(tptr, &msg->transfers){ ++ entry = list_entry(tptr, struct spi_transfer, transfer_list); ++ if(entry->tx_buf && entry->rx_buf){ //duplex ++ for(i=0; i< entry->len; i++){ ++ tx(((char*) entry->tx_buf)+i*sizeof(char),1); ++ rx(((char*) entry->rx_buf)+i*sizeof(char),1); ++ } ++ msg->actual_length += entry->len; ++ } else if(entry->tx_buf && !entry->rx_buf){ //write ++ tx((char*) entry->tx_buf, entry->len); ++ msg->actual_length += entry->len; ++ } else if(!entry->tx_buf && entry->rx_buf){ //read ++ rx((char*) entry->rx_buf, entry->len); ++ msg->actual_length += entry->len; ++ } else if(!entry->tx_buf && !entry->rx_buf){ //error ++ dev_err(&spidev->sdev->dev, "do_transfer: no buffers allocated\n"); ++ msg->status = -EFAULT; ++ } ++ } ++ spin_lock(&spidev->message_lock); ++ list_del(mptr); ++ spin_unlock(&spidev->message_lock); ++ msg->complete(msg->context); ++ } ++} ++ ++static int locomospi_setup(struct spi_device *spi) ++{ ++ if((spi->mode & SPI_CS_HIGH) != (spidev->spimode & SPI_CS_HIGH)) ++ locomospi_togglecs(); ++ spidev->spimode = spi->mode; ++ ++ if(spi->max_speed_hz == 0) ++ locomospi_setclock(0, 0); ++ else if(spi->max_speed_hz >= 25000000) ++ locomospi_setclock(0, 2); ++ else if(spi->max_speed_hz >= 22500000) ++ locomospi_setclock(0, 1); ++ else if(spi->max_speed_hz >= 12500000) ++ locomospi_setclock(1, 2); ++ else if(spi->max_speed_hz >= 10000000) ++ locomospi_setclock(1, 1); ++ else if(spi->max_speed_hz >= 9000000) ++ locomospi_setclock(1, 0); ++ else if(spi->max_speed_hz >= 6230000) ++ locomospi_setclock(2, 2); ++ else if(spi->max_speed_hz >= 5660000) ++ locomospi_setclock(2, 1); ++ else if(spi->max_speed_hz >= 4640000) ++ locomospi_setclock(2, 0); ++ else if(spi->max_speed_hz >= 3030000) ++ locomospi_setclock(3, 2); ++ else if(spi->max_speed_hz >= 2870000) ++ locomospi_setclock(3, 1); ++ else if(spi->max_speed_hz >= 2330000) ++ locomospi_setclock(3, 0); ++ else if(spi->max_speed_hz >= 383000) ++ locomospi_setclock(4, 2); ++ else if(spi->max_speed_hz >= 350000) ++ locomospi_setclock(4, 1); ++ else ++ locomospi_setclock(4, 0); ++ return 0; ++} ++ ++static int locomospi_transfer(struct spi_device *spi, struct spi_message *msg) ++{ ++ ++ spin_lock(&spidev->message_lock); ++ list_add_tail(&msg->queue, &spidev->message_list); ++ spin_unlock(&spidev->message_lock); ++ schedule_work(&transfer_wq); ++ return 0; ++} ++ ++static struct locomo_driver locomo_spi_driver = { ++ .drv = { ++ .name = "locomo-spi", ++ }, ++ .devid = LOCOMO_DEVID_SPI, ++ .probe = locomospi_probe, ++ .remove = locomospi_remove, ++#ifdef CONFIG_PM ++ .suspend = locomospi_suspend, ++ .resume = locomospi_resume, ++#endif ++}; ++ ++static struct spi_board_info board = { ++ .modalias = "mmc_spi", ++ .platform_data = (void*) &colliemmc, ++ .controller_data= NULL, ++ .irq = 0, ++ .max_speed_hz = 25000000, ++ .bus_num = 0, ++ .chip_select = 0, ++ .mode = 0, ++}; ++ ++#ifdef CONFIG_PM ++static int locomospi_suspend(struct locomo_dev *dev, pm_message_t state) ++{ ++ disable_irq(IRQ_LOCOMO_CARDDETECT); ++ return 0; ++} ++ ++static int locomospi_resume(struct locomo_dev *dev) ++{ ++ enable_irq(IRQ_LOCOMO_CARDDETECT); ++ return 0; ++} ++#endif ++ ++static int locomospi_probe(struct locomo_dev *dev) ++{ ++ int result=0; ++ printk(KERN_DEBUG "Collie MMC over SPI Driver\n"); ++ spidev=kmalloc(sizeof(struct locomospi_dev),GFP_KERNEL); ++ if(!spidev){ ++ return -ENOMEM; ++ } ++ spidev->ldev = dev; ++ spidev->card_power = 0; ++ spidev->spimode = 0; ++ if(!request_mem_region((unsigned long) dev->mapbase, dev->length, LOCOMO_DRIVER_NAME(dev))) { ++ dev_err(&dev->dev, " Can't aquire access to io memory\n"); ++ return -EBUSY; ++ } ++ spidev->base=(unsigned long) dev->mapbase; ++ ++ locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_CARD_POWER, 0); ++ locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_CARD_DETECT, 1); ++ locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_WRITE_PROTECT, 1); ++ ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_cardpower); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_carddetect); ++ if(result){ ++ dev_err(&dev->dev,"error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_cardwriteprotect); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spimd); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spict); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spist); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spiis); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spiwe); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spiie); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spiir); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spitd); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spird); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spits); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spirs); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_clockbase); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_clockmult); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_reset); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_verbose); ++ if(result){ ++ dev_err(&dev->dev, "error creating driver attribute\n"); ++ goto region; ++ } ++ INIT_WORK(&transfer_wq, locomospi_do_transfer); ++ INIT_LIST_HEAD(&spidev->message_list); ++ spin_lock_init(&spidev->message_lock); ++ init_waitqueue_head(&spidev->waitqueue); ++ spidev->master=spi_alloc_master(&dev->dev,0); ++ if(!spidev->master){ ++ result=-ENOMEM; ++ goto region; ++ } ++ spidev->master->bus_num = 0; ++ spidev->master->num_chipselect = 0; ++ spidev->master->setup = locomospi_setup; ++ spidev->master->transfer = locomospi_transfer; ++ spidev->sdev = spi_new_device(spidev->master, &board); ++ if(!spidev->sdev){ ++ dev_err(&dev->dev, "failed to register spi device\n"); ++ goto master; ++ } ++/* result=request_irq(IRQ_LOCOMO_SPI_RFR, locomospi_rwready, SA_SHIRQ, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: RFR\n"); ++ goto regdev; ++ } ++ result=request_irq(IRQ_LOCOMO_SPI_RFW, locomospi_rwready, SA_SHIRQ, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: RFW\n"); ++ goto irq1; ++ } ++ result=request_irq(IRQ_LOCOMO_SPI_OVRN, locomospi_testisr, SA_SHIRQ, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: OVRN\n"); ++ goto irq2; ++ }*/ ++/* result=request_irq(IRQ_LOCOMO_SPI_TEND, locomospi_testisr, SA_SHIRQ, "locomo-spi", (void*) spidev); ++ if(result) { ++ dev_err(&dev->dev, "Could not get IRQ: TEND\n"); ++ goto irq3; ++ }*/ ++ locomospi_reg_open(); ++ spidev->workqueue = create_singlethread_workqueue("locomo-spi"); ++ if(!spidev->workqueue){ ++ dev_err(&dev->dev, "failed to create workqueue\n"); ++ goto irq3; ++ } ++ result=spi_register_master(spidev->master); ++ if(result){ ++ dev_err(&dev->dev, "failed to register spimaster\n"); ++ goto wq; ++ } ++ return 0; ++wq: ++ destroy_workqueue(spidev->workqueue); ++irq3: ++// free_irq(IRQ_LOCOMO_SPI_OVRN, (void*) spidev); ++//irq2: ++// free_irq(IRQ_LOCOMO_SPI_RFW, (void*) spidev); ++//irq1: ++// free_irq(IRQ_LOCOMO_SPI_RFR, (void*) spidev); ++//regdev: ++ spi_unregister_device(spidev->sdev); ++master: ++ spi_master_put(spidev->master); ++region: ++ release_mem_region((unsigned long) dev->mapbase, dev->length); ++ kfree(spidev); ++ return result; ++ ++} ++ ++static int locomospi_remove(struct locomo_dev *dev) ++{ ++ spi_unregister_device(spidev->sdev); ++ spi_unregister_master(spidev->master); ++ destroy_workqueue(spidev->workqueue); ++ locomospi_reg_release(); ++// free_irq(IRQ_LOCOMO_SPI_TEND, (void*) spidev); ++// free_irq(IRQ_LOCOMO_SPI_OVRN, (void*) spidev); ++// free_irq(IRQ_LOCOMO_SPI_RFW, (void*) spidev); ++// free_irq(IRQ_LOCOMO_SPI_RFR, (void*) spidev); ++ spi_master_put(spidev->master); ++ release_mem_region((unsigned long) dev->mapbase, dev->length); ++ kfree(spidev); ++ return 0; ++} ++ ++ ++ ++static int __init locomospi_init(void) ++{ ++ int ret = locomo_driver_register(&locomo_spi_driver); ++ if (ret) ++ return ret; ++ ++ ++ return 0; ++} ++ ++static void __exit locomospi_exit(void) ++{ ++ locomo_driver_unregister(&locomo_spi_driver); ++} ++ ++module_init(locomospi_init); ++module_exit(locomospi_exit); ++ ++MODULE_AUTHOR("Thomas Kunze thommy@tabao.de"); ++MODULE_DESCRIPTION("Collie mmc driver"); ++MODULE_LICENSE("GPL"); +Index: linux-2.6.21/drivers/spi/locomo_spi.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/spi/locomo_spi.h 2007-07-03 21:40:52.000000000 +0200 +@@ -0,0 +1,37 @@ ++#include <asm/hardware/locomo.h> ++#ifndef __LOCOMO_SPI_H__ ++#define __LOCOMO_SPI_H__ ++#define IRQ_LOCOMO_CARDDETECT IRQ_LOCOMO_GPIO13 ++#define HIGH 1 ++#define LOW 0 ++struct locomospi_dev { ++ struct locomo_dev *ldev; ++ struct spi_master *master; ++ struct spi_device *sdev; ++ int card_power; ++ int clock_base; ++ int clock_mult; ++ unsigned long base; ++ u8 spimode; ++ wait_queue_head_t waitqueue; ++ struct workqueue_struct *workqueue; ++ struct list_head message_list; ++ spinlock_t message_lock; ++ irqreturn_t (*mmc_spi_isr)(int, void*); ++}; ++ ++ ++static irqreturn_t locomospi_cardisr(int, void*); ++static int locomospi_probe(struct locomo_dev*); ++static int locomospi_remove(struct locomo_dev*); ++static int locomospi_carddetect(void); ++static void locomospi_reg_open(void); ++static void locomospi_reg_release(void); ++static int tx(const char*, int); ++static int rx(char *, int); ++static void locomospi_togglecs(void); ++static void locomospi_power(int on); ++static int locomospi_suspend(struct locomo_dev *dev, pm_message_t state); ++static int locomospi_resume(struct locomo_dev *dev); ++static void locomospi_setcs(int high); ++#endif +Index: linux-2.6.21/drivers/spi/Makefile +=================================================================== +--- linux-2.6.21.orig/drivers/spi/Makefile 2007-04-26 05:08:32.000000000 +0200 ++++ linux-2.6.21/drivers/spi/Makefile 2007-07-03 21:41:16.000000000 +0200 +@@ -20,6 +20,7 @@ + obj-$(CONFIG_SPI_MPC83xx) += spi_mpc83xx.o + obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o + obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o ++obj-$(CONFIG_SPI_LOCOMO) += locomo_spi.o + # ... add above this line ... + + # SPI protocol drivers (device/link on bus) |