--- linux-2.6.18_orig/arch/avr32/boards/atstk1000/atstk1002.c 2007-01-26 11:54:14.000000000 +0100 +++ scspi_patch/arch/avr32/boards/atstk1000/atstk1002.c 2007-02-07 17:22:13.000000000 +0100 @@ -23,13 +23,22 @@ extern struct lcdc_platform_data atstk1000_fb0_data; + static struct spi_board_info spi_board_info[] __initdata = { { - .modalias = "ltv350qv", - .controller_data = (void *)GPIO_PIN_PA(4), - .max_speed_hz = 16000000, - .bus_num = 0, - .chip_select = 1, + .modalias = "ltv350qv", + .controller_data = (void *)GPIO_PIN_PA(4), /* CS pin */ + .max_speed_hz = 16000000, + .bus_num = 0, + .chip_select = 1, /* chip select number spi. */ + }, + + { + .modalias = "scspi", + .max_speed_hz = 16000000, + .controller_data = (void *)GPIO_PIN_PA(5), /* CS pin on chip*/ + .bus_num = 0, + .chip_select = 2, /* chip select number spi. */ }, }; @@ -74,6 +83,7 @@ at32_add_device_mmci(0); at32_add_device_spi(0); + at32_add_device_twi(0); at32_add_device_usb(0); at32_add_device_lcdc(0, &atstk1000_fb0_data); --- linux-2.6.18_orig/drivers/spi/scspi.h 1970-01-01 01:00:00.000000000 +0100 +++ scspi_patch/drivers/spi/scspi.h 2007-02-07 10:56:48.000000000 +0100 @@ -0,0 +1,95 @@ +#ifndef __KM_SCSPI_H_ +#define __KM_SCSPI_H_ + + +// Includes + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +// Defines + +#define SCSPI_LOGLEVEL KERN_ALERT +#define SCSPI_MODE SPI_MODE_0 +#define SCSPI_SIZE 0x08 +#define SCSPI_FILLER 0xC0 +#define SCSPI_BAUD 0xE00000 //14 * 1048576 (14 Mbit\s, should push for full 24 Mbit\s) +#define SCSPI_CHIP 0x02 +#define SCSPI_IOCTL_MAGIC 0xF5 +#define SCSPI_IOCTL_MAXNR 0x0B + +// Ioctl commands +#define IOCSMODE _IOW(SCSPI_IOCTL_MAGIC, 1, __i32) +#define IOCSSIZE _IOW(SCSPI_IOCTL_MAGIC, 2, __i32) +#define IOCSFILLER _IOW(SCSPI_IOCTL_MAGIC, 3, __i32) +#define IOCSBAUD _IOW(SCSPI_IOCTL_MAGIC, 4, __i32) +#define IOCSCHIP _IOW(SCSPI_IOCTL_MAGIC, 5, __i32) +#define IOCTMODE _IOR(SCSPI_IOCTL_MAGIC, 6, __i32) +#define IOCTSIZE _IOR(SCSPI_IOCTL_MAGIC, 7, __i32) +#define IOCTFILLER _IOR(SCSPI_IOCTL_MAGIC, 8, __i32) +#define IOCTBAUD _IOR(SCSPI_IOCTL_MAGIC, 9, __i32) +#define IOCTCHIP _IOR(SCSPI_IOCTL_MAGIC, 10, __i32) +#define IOCTCONTEXT _IO(SCSPI_IOCTL_MAGIC, 11) + +#define true 0x01 +#define false 0x00 + + +// Macros + +#ifdef SCSPI_DEBUG + #define scspiDebug(fmt, args...) { if(printk_ratelimit()) printk(SCSPI_LOGLEVEL "scspi: " fmt, ## args); } +#else + #define scspiDebug(fmt, args...) +#endif + +#define scspiEcho(fmt, args...) printk(SCSPI_LOGLEVEL "scspi: " fmt, ## args) + + +// Typedefs + +typedef int __i32; +typedef long long int __i64; +typedef unsigned long __ul32; + +typedef struct scspi_device { + dev_t number; + struct cdev * khandle; + struct spi_device * spi; + struct semaphore mutex; + __u8 busy; + __u8 * rx; + __u8 * tx; + __u8 filler; +} scspi_device; + + +// Variables + + +// Function declarations + +static __i32 __devinit scspiProbe(struct spi_device *); +static __i32 __devexit scspiRemove(struct spi_device *); +static __i32 __init scspiLoad(void); +static void __exit scspiUnload(void); +static ssize_t scspiRead(struct file *, char __user *, size_t, __i64 *); +static ssize_t scspiWrite(struct file *, const char __user *, size_t, __i64 *); +static __i32 scspiOpen(struct inode *, struct file *); +static __i32 scspiRelease(struct inode *, struct file *); +static __i32 scspiIoctl(struct inode *, struct file *, __u32, __ul32); +static void scspiDebugRegisters(void); + + +#endif // __KM_SCSPI_H_ --- linux-2.6.18_orig/drivers/spi/scspi.c 1970-01-01 01:00:00.000000000 +0100 +++ scspi_patch/drivers/spi/scspi.c 2006-12-26 02:15:56.000000000 +0100 @@ -0,0 +1,477 @@ +/*-- + +scspi.c - Sciensis Linux kernel SPI protocol driver to interface microcontrollers to the avr32 + +Author: Tasos Parisinos (t.parisinos@sciensis.com) +Last update: 26/12/2006 3:14 am +Platform: avr32 (stk1000-2) + +*/ + +#include "scspi.h" + + +// Variables + +static struct scspi_device * device; + +static struct file_operations fops = { + .owner = THIS_MODULE, + .read = scspiRead, + .write = scspiWrite, + .open = scspiOpen, + .release = scspiRelease, + .ioctl = scspiIoctl, +}; + +static struct spi_driver scspi_driver = { + .probe = scspiProbe, + .remove = __devexit_p(scspiRemove), + .driver = { + .name = "scspi", + } +}; + + +// Macros + + +// Function declarations + + +// Functions + +/*-- + Driver loading callback function + Returns 0 on success or a negative value indicating error +*/// +static __i32 __devinit scspiProbe(struct spi_device * spi) // Interface to the spi master controller driver +{ + __i32 retval; + + // Initialize the spi struct + device->spi = spi; + spi->mode = SCSPI_MODE; + spi->bits_per_word = SCSPI_SIZE; + spi->max_speed_hz = SCSPI_BAUD; + spi->chip_select = SCSPI_CHIP; + + // Setup the SPI driver and channel + if((retval = spi_setup(spi)) < 0) + { + scspiDebug("scspiProbe: spi_setup failed (%d)\n", retval); + return retval; + } + + dev_set_drvdata(&spi->dev, device); + return 0; +} + + + +/*-- + Driver unloading callback function + Returns 0 on success or a negative value indicating error +*/// +static __i32 __devexit scspiRemove(struct spi_device * spi) // Interface to the spi master controller driver +{ + return 0; +} + + + +/*-- + Module loading callback function + Returns 0 on success or a negative value indicating error +*/// +static __i32 __init scspiLoad(void) +{ + __i32 retval; + + if(!(device = kzalloc(sizeof(struct scspi_device), GFP_KERNEL))) + { + scspiDebug("scspiLoad: kzalloc failed\n"); + return -ENOMEM; + } + + init_MUTEX(&device->mutex); + device->filler = SCSPI_FILLER; + + // Major/minor number allocation + if((retval = alloc_chrdev_region(&device->number, 0, 1, "scspi")) < 0) + { + scspiDebug("scspiLoad: alloc_chrdev_region failed (%d)\n", retval); + goto alloc_chrdev_failed; + } + scspiDebug("Allocated device major %d, minor %d\n", MAJOR(device->number), MINOR(device->number)); + + device->khandle = cdev_alloc(); + device->khandle->ops = &fops; + device->khandle->owner = THIS_MODULE; + + // Character device kernel registration + if((retval = cdev_add(device->khandle, device->number, 1)) < 0) + { + scspiDebug("scspiLoad: cdev_add failed (%d)\n", retval); + goto cdev_add_failed; + } + + // Registration of the driver with the linux device model + if((retval = spi_register_driver(&scspi_driver)) < 0) + { + scspiDebug("scspiLoad: spi_register_driver failed (%d)\n", retval); + goto spi_register_driver_failed; + } + goto success; + +// Rollback in case of any failure +spi_register_driver_failed: + cdev_del(device->khandle); +cdev_add_failed: + unregister_chrdev_region(device->number, 1); +alloc_chrdev_failed: + kfree(device); + return retval; +success: + scspiEcho("Sciensis spi protocol driver initialized\n"); + return 0; +} + + + +/*-- + Module unloading callback function +*/// +static void __exit scspiUnload(void) +{ + // Unregister the driver from the linux device model + spi_unregister_driver(&scspi_driver); + + // Unregister the character device from the kernel + cdev_del(device->khandle); + + // Unregister major/minor numbers allocated + unregister_chrdev_region(device->number, 1); + + kfree(device); + scspiEcho("Sciensis spi protocol driver unloaded\n"); +} + + + +/*-- + Read an arbitrary number of bytes from the selected slave + Returns 0 on success or a negative value indicating error +*/// +static ssize_t scspiRead(struct file * f, // File descriptor of the device file + char __user * buffer, // Pointer to the userland buffer where the received bytes will be stored + size_t bytes, // sizeof buffer + __i64 * offset) // Device file stream offset +{ + __u32 retval; + struct spi_message msg; + struct spi_transfer transfer; + + if(down_interruptible(&device->mutex)) + { + retval = -ERESTARTSYS; + goto down_interrupted; + } + + // Allocate tx, rx buffers + if(!(device->tx = kzalloc(bytes, GFP_KERNEL)) || !(device->rx = kzalloc(bytes, GFP_KERNEL))) + { + scspiDebug("scspiRead: kzalloc failed\n"); + retval = -ENOMEM; + goto kzalloc_failed; + } + + // Fill the transmit buffer with filler data. Initialize a transfer to write + // those filler data while reading data sent from the slave If the slave has no + // data to send or less data than those requested by the userland the returned + // data are padded with filler bytes + memset(device->tx, device->filler, bytes); + memset(&transfer, 0, sizeof(transfer)); + transfer.len = bytes; + transfer.tx_buf = device->tx; + transfer.rx_buf = device->rx; + spi_message_init(&msg); + spi_message_add_tail(&transfer, &msg); + + // Do the transfer + if((retval = spi_sync(device->spi, &msg)) < 0) + { + scspiDebug("scspiRead: spi_sync failed (%d)\n", retval); + goto spi_sync_failed; + } + + // Copy data back to the userland memspace + if((retval = copy_to_user(buffer, device->rx, bytes))) + { + scspiDebug("scspiRead: copy_to_user failed (%d)\n", retval); + retval = -EFAULT; + goto copy_to_user_failed; + } + + kfree(device->tx); + kfree(device->rx); + up(&device->mutex); + return bytes; + +// Rollback in case of any failure +copy_to_user_failed: +spi_sync_failed: + kfree(device->tx); + kfree(device->rx); +kzalloc_failed: + up(&device->mutex); +down_interrupted: + return retval; +} + + + +/*-- + Send an arbitrary number of bytes to the selected slave + Returns 0 on success or a negative value indicating error +*/// +static ssize_t scspiWrite(struct file * f, // File descriptor of the device file + const char __user * buffer, // Pointer to the user data to be sent + size_t bytes, // sizeof buffer + __i64 * offset) // Device file stream offset +{ + __u32 retval; + struct spi_message msg; + struct spi_transfer transfer; + + if(down_interruptible(&device->mutex)) + { + retval = -ERESTARTSYS; + goto down_interrupted; + } + + // Allocate only the tx buffer (ignore incoming data) + if(!(device->tx = kzalloc(bytes, GFP_KERNEL))) + { + scspiDebug("scspiWrite: kzalloc failed\n"); + retval = -ENOMEM; + goto kzalloc_failed; + } + + // Copy data from the userland memspace + if((retval = copy_from_user(device->tx, buffer, bytes))) + { + scspiDebug("scspiWrite: copy_from_user failed (%d)\n", retval); + retval = -EFAULT; + goto copy_from_user_failed; + } + +#if defined(SCSPI_HW_ACCESS) && defined(SCSPI_LOCAL_LOOPBACK) + device->iomembase->mr |= (1 << AVR32_SPI_MR_LLB_OFFSET); +#endif + + // Initialize a transfer and call the spi master controller driver to send the data + memset(&transfer, 0, sizeof(transfer)); + transfer.len = bytes; + transfer.tx_buf = device->tx; + spi_message_init(&msg); + spi_message_add_tail(&transfer, &msg); + + // Do the transfer + if((retval = spi_sync(device->spi, &msg)) < 0) + scspiDebug("scspiWrite: spi_sync failed (%d)\n", retval); + + kfree(device->tx); + up(&device->mutex); + return (retval < 0)? retval: bytes; + +// Rollback in case of any failure +copy_from_user_failed: + kfree(device->tx); +kzalloc_failed: + up(&device->mutex); +down_interrupted: + return retval; +} + + + +/*-- + Mark the device as being used. This will block any other processes to open the device file + but due to fork and dup multiple accesses of the device can still occur + Returns 0 on success or a negative value indicating error +*/// +static __i32 scspiOpen(struct inode * node, // Inode of the device file + struct file * f) // File descriptor of the device file +{ + if(down_interruptible(&device->mutex)) + return -ERESTARTSYS; + + if(device->busy) + { + up(&device->mutex); + return -EBUSY; + } + + device->busy = true; + up(&device->mutex); + return 0; +} + + + +/*-- + Releases the device when all references of the device file are closed + Returns 0 on success or a negative value indicating error +*/// +static __i32 scspiRelease(struct inode * node, // Inode of the device file + struct file * f) // File descriptor of the device file +{ + if(down_interruptible(&device->mutex)) + return -ERESTARTSYS; + + device->busy = false; + up(&device->mutex); + return 0; +} + + + +/*-- + ioctl system call implementation + Returns 0 on success or a negative value indicating error +*/// +static __i32 scspiIoctl(struct inode * node, // Inode of the device file + struct file * f, // File descriptor of the device file + __u32 cmd, // Id of the command to execute + __ul32 arg) // Argument to pass to the device or read to from the device +{ + __i32 retval = 0; + + // Check for command validity + if(_IOC_TYPE(cmd) != SCSPI_IOCTL_MAGIC || _IOC_NR(cmd) > SCSPI_IOCTL_MAXNR) + return -ENOTTY; + + // Check if the argument is sane + if((cmd == IOCSMODE && (arg < SPI_MODE_0 || arg > SPI_MODE_3)) || + (cmd == IOCSSIZE && (arg < 8 || arg > 16)) || + (cmd == IOCSCHIP && arg > 3)) + return -EINVAL; + + if(down_interruptible(&device->mutex)) + return -ERESTARTSYS; + + // Commands that set the device configuration + if(cmd >= IOCSMODE && cmd <= IOCSBAUD) + { + switch(cmd) + { + // Set mode + case IOCSMODE: + device->spi->mode = arg; + break; + + // Set word bit size + case IOCSSIZE: + device->spi->bits_per_word = arg; + break; + + // Set filler byte + case IOCSFILLER: + device->filler = arg; + break; + + // Set baud rate + case IOCSBAUD: + device->spi->max_speed_hz = arg; + break; + + // Set chip select + case IOCSCHIP: + device->spi->chip_select = arg; + break; + + default: + retval = -ENOTTY; + } + + // Setup the SPI driver and channel + if((retval = spi_setup(device->spi)) < 0) + scspiDebug("scspiIoctl: spi_setup failed (%d)\n", retval); + } + // Commands to query the device configuration and register context + else if(cmd >= IOCTMODE && cmd <= IOCTCONTEXT) + { + switch(cmd) + { + // Tell mode + case IOCTMODE: + retval = put_user(device->spi->mode, (__u32 *)arg); + break; + + // Tell word bit size + case IOCTSIZE: + retval = put_user(device->spi->bits_per_word, (__u32 *)arg); + break; + + // Tell filler byte + case IOCTFILLER: + retval = put_user(device->filler, (__u32 *)arg); + break; + + // Tell baud rate + case IOCTBAUD: + retval = put_user(device->spi->max_speed_hz, (__u32 *)arg); + break; + + // Tell chip select + case IOCTCHIP: + retval = put_user(device->spi->chip_select, (__u32 *)arg); + break; + + // Print out the device registers + case IOCTCONTEXT: + scspiDebugRegisters(); + break; + + default: + retval = -ENOTTY; + } + + if(retval < 0) + scspiDebug("scspiIoctl: put_user failed (%d)\n", retval); + } + else + retval = -ENOTTY; + + up(&device->mutex); + return retval; +} + + + +/*-- + Print to console the context of the spi device +*/// +static void scspiDebugRegisters(void) +{ +#if defined(SCSPI_HW_ACCESS) && defined(SCSPI_DEBUG) + volatile avr32_spi_t * spi = &AVR32_SPI0; + scspiDebug("CR := 0x%x\t\tMR := 0x%x\n", (__u32)spi->cr, (__u32)spi->mr); + scspiDebug("RDR := 0x%x\t\tTDR := 0x%x\n", (__u32)spi->rdr, (__u32)spi->tdr); + scspiDebug("SR := 0x%x\t\tIER := 0x%x\n", (__u32)spi->sr, (__u32)spi->ier); + scspiDebug("IDR := 0x%x\t\tIMR := 0x%x\n", (__u32)spi->idr, (__u32)spi->imr); + scspiDebug("CSR0 := 0x%x\t\tCSR1 := 0x%x\n", (__u32)spi->csr0, (__u32)spi->csr1); + scspiDebug("CSR2 := 0x%x\t\tCSR3 := 0x%x\n", (__u32)spi->csr2, (__u32)spi->csr3); +#elif defined(SCSPI_DEBUG) + scspiDebug("Cannot access spi hw registers\n"); +#endif +} + + +module_init(scspiLoad); +module_exit(scspiUnload); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tasos Parisinos @ Sciensis Advanced Technology Systems"); +MODULE_DESCRIPTION("Spi protocol driver to interface another microcontroller"); --- linux-2.6.18_orig/drivers/spi/Kconfig 2007-01-26 11:54:15.000000000 +0100 +++ scspi_patch/drivers/spi/Kconfig 2007-02-02 15:28:18.000000000 +0100 @@ -128,6 +128,46 @@ comment "SPI Protocol Masters" depends on SPI_MASTER +config SPI_SCIENSIS + tristate "Sciensis SPI protocol driver" + depends on SPI_ATMEL + help + This selects a protocol driver created by + Sciensis Advanced Technology Systems to + connect the AVR32STK1000 to other development + boards. If it is selected it will add + approximately 7K to the kernel size. + + Select M to build this driver as a module. + If unsure say N. + +config SPI_SCIENSIS_DEBUG + bool "Debug driver" + depends on SPI_SCIENSIS + help + This adds lots of debugging information into + the driver. It also adds approximately 80K + to the kernel, so it should be avoided to + optimize kernel size. + +config SPI_SCIENSIS_HW_ACCESS + bool "Driver hardware access" + depends on SPI_SCIENSIS + help + Although an SPI protocol driver does not need to + touch hardware registers (and also should not :) + setting this options is essential to have thorough + debugging information and to be able to use the + local loopback feature of the spi device. + +config SPI_SCIENSIS_LOOPBACK + bool "Enable the local loopback of the spi device" + depends on SPI_SCIENSIS && SPI_SCIENSIS_HW_ACCESS + help + Enable the local loopback feature of the spi device, + used to test code only. + + # # Add new SPI protocol masters in alphabetical order above this line --- linux-2.6.18_orig/drivers/spi/Makefile 2007-01-26 11:54:15.000000000 +0100 +++ scspi_patch/drivers/spi/Makefile 2007-02-07 14:45:04.000000000 +0100 @@ -6,6 +6,23 @@ EXTRA_CFLAGS += -DDEBUG endif +ifeq ($(CONFIG_SPI_SCIENSIS),y) +EXTRA_CFLAGS += -I/usr/local/avr32/include +EXTRA_CFLAGS += -D__AVR32_AP7000__ +endif + +ifeq ($(CONFIG_SPI_SCIENSIS_DEBUG),y) +EXTRA_CFLAGS += -DSCSPI_DEBUG +endif + +ifeq ($(CONFIG_SPI_SCIENSIS_HW_ACCESS),y) +EXTRA_CFLAGS += -DSCSPI_HW_ACCESS +endif + +ifeq ($(CONFIG_SPI_SCIENSIS_LOOPBACK),y) +EXTRA_CFLAGS += -DSCSPI_LOOPBACK +endif + # small core, mostly translating board-specific # config declarations into driver model code obj-$(CONFIG_SPI_MASTER) += spi.o @@ -21,6 +38,7 @@ # ... add above this line ... # SPI protocol drivers (device/link on bus) +obj-$(CONFIG_SPI_SCIENSIS) += scspi.o # ... add above this line ... # SPI slave controller drivers (upstream link) @@ -28,3 +46,7 @@ # SPI slave drivers (protocol for that link) # ... add above this line ... + + + +