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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; ibase+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; ibase+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 +#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)