diff -uprN -X linux.orig/Documentation/dontdiff \ linux.orig/arch/avr32/boards/atstk1000/atstk1002.c \ linux/arch/avr32/boards/atstk1000/atstk1002.c --- linux.orig/arch/avr32/boards/atstk1000/atstk1002.c \ 2007-04-16 14:40:58.000000000 +0300 +++ linux/arch/avr32/boards/atstk1000/atstk1002.c \ 2007-04-16 14:54:44.000000000 +0300 @@ -42,6 +42,13 @@ static struct spi_board_info spi0_board_ .max_speed_hz = 16000000, .chip_select = 1, }, + + { + .modalias = "scspi", + .max_speed_hz = 16000000, + .bus_num = 0, + .chip_select = 2, + }, }; static struct mci_platform_data __initdata mci0_data = { diff -uprN -X linux.orig/Documentation/dontdiff \ linux.orig/drivers/spi/Kconfig linux/drivers/spi/Kconfig --- linux.orig/drivers/spi/Kconfig 2007-04-16 14:40:58.000000000 +0300 +++ linux/drivers/spi/Kconfig 2007-04-16 15:27:07.000000000 +0300 @@ -128,6 +128,19 @@ config SPI_S3C24XX comment "SPI Protocol Masters" depends on SPI_MASTER +config SPI_SCSPI + tristate "Sciensis SPI protocol driver" + depends on SPI_ATMEL + help + This driver can be used to create a network of spi + interfaces. As an example it can be used to create + a connection between two or more microcontrollers + equipped with spi interfaces. It can also be used + to communicate with any spi interfaced device. It + also creates a devfs interface point. + + Select M to build this driver as a module. + If unsure say N. # # Add new SPI protocol masters in alphabetical order above this line diff -uprN -X linux.orig/Documentation/dontdiff \ linux.orig/drivers/spi/Makefile linux/drivers/spi/Makefile --- linux.orig/drivers/spi/Makefile 2007-04-16 14:40:58.000000000 +0300 +++ linux/drivers/spi/Makefile 2007-04-16 17:07:31.000000000 +0300 @@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24x # ... add above this line ... # SPI protocol drivers (device/link on bus) +obj-$(CONFIG_SPI_SCSPI) += scspi.o # ... add above this line ... # SPI slave controller drivers (upstream link) diff -uprN -X linux.orig/Documentation/dontdiff \ linux.orig/drivers/spi/scspi.c linux/drivers/spi/scspi.c --- linux.orig/drivers/spi/scspi.c 1970-01-01 02:00:00.000000000 +0200 +++ linux/drivers/spi/scspi.c 2007-04-17 10:53:36.000000000 +0300 @@ -0,0 +1,380 @@ +/* + * SPI drivers + * + * SPI protocol driver to create networks of spi interfaces + * + * Copyright (c) 2007 Tasos Parisinos + * Copyright (c) 2007 Sciensis Advanced Technology Systems + * + * 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 + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MODE SPI_MODE_0 +#define SIZE 8 +#define FILLER 0xC0 +#define BAUD 0xE00000 /* 14 Mbits */ +#define CHIP 2 +#define IOCTL_BASE 0xF5 +#define IOCTL_MAXNR 10 + +#define IOCTL_SET_MODE _IOW(IOCTL_BASE, 1, int) +#define IOCTL_SET_SIZE _IOW(IOCTL_BASE, 2, int) +#define IOCTL_SET_FILLER _IOW(IOCTL_BASE, 3, int) +#define IOCTL_SET_BAUD _IOW(IOCTL_BASE, 4, int) +#define IOCTL_SET_CHIP _IOW(IOCTL_BASE, 5, int) +#define IOCTL_GET_MODE _IOR(IOCTL_BASE, 6, int) +#define IOCTL_GET_SIZE _IOR(IOCTL_BASE, 7, int) +#define IOCTL_GET_FILLER _IOR(IOCTL_BASE, 8, int) +#define IOCTL_GET_BAUD _IOR(IOCTL_BASE, 9, int) +#define IOCTL_GET_CHIP _IOR(IOCTL_BASE, 10, int) + +struct scspi_device { + dev_t number; + struct cdev *khandle; + struct spi_device *spi; + struct semaphore mutex; + u8 busy; + u8 *rx; + u8 *tx; + u8 filler; +}; + +static struct scspi_device *device; + +static int __devinit scspi_probe(struct spi_device *spi) +{ + int retval; + + device->spi = spi; + spi->mode = MODE; + spi->bits_per_word = SIZE; + spi->max_speed_hz = BAUD; + spi->chip_select = CHIP; + + retval = spi_setup(spi); + if (retval < 0) + return retval; + + dev_set_drvdata(&spi->dev, device); + return 0; +} + +static int __devexit scspi_remove(struct spi_device *spi) +{ + return 0; +} + +/* + * Mark the device as being used, blocking any other processes from opening the + * device file. Due to fork and dup multiple accesses of the device can still + * occur. + */ +static int scspi_open(struct inode *node, struct file *f) +{ + if (down_interruptible(&device->mutex)) + return -ERESTARTSYS; + if (device->busy) { + up(&device->mutex); + return -EBUSY; + } + + device->busy = true; + up(&device->mutex); + return 0; +} + +static int scspi_release(struct inode *node, struct file *f) +{ + if (down_interruptible(&device->mutex)) + return -ERESTARTSYS; + + device->busy = false; + up(&device->mutex); + return 0; +} + +/* Read an arbitrary number of bytes from the selected slave */ +static ssize_t scspi_read(struct file *f, char __user *buffer, size_t bytes, + long long *offset) +{ + int retval; + struct spi_message msg; + struct spi_transfer transfer; + + if (down_interruptible(&device->mutex)) { + retval = -ERESTARTSYS; + goto down_interrupted; + } + + /* Allocate tx, rx buffers */ + device->tx = kzalloc(bytes, GFP_KERNEL); + device->rx = kzalloc(bytes, GFP_KERNEL); + if (!device->tx || !device->rx) { + 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(struct spi_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 */ + retval = spi_sync(device->spi, &msg); + if (retval < 0) + goto spi_sync_failed; + + /* Copy data back to the userland memspace */ + retval = copy_to_user(buffer, device->rx, bytes); + if (retval < 0) { + 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; +} + +static ssize_t scspi_write(struct file *f, const char __user *buffer, + size_t bytes, long long *offset) +{ + int 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) */ + device->tx = kzalloc(bytes, GFP_KERNEL); + if (!device->tx) { + retval = -ENOMEM; + goto kzalloc_failed; + } + + /* Copy data from the userland memspace */ + retval = copy_from_user(device->tx, buffer, bytes); + if (retval < 0) { + retval = -EFAULT; + goto copy_from_user_failed; + } + + /* + * Initialize a transfer and call the spi master controller driver to + * send the data + */ + memset(&transfer, 0, sizeof(struct spi_transfer)); + transfer.len = bytes; + transfer.tx_buf = device->tx; + spi_message_init(&msg); + spi_message_add_tail(&transfer, &msg); + + /* Do the transfer */ + retval = spi_sync(device->spi, &msg); + + 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; +} + +static int scspi_ioctl(struct inode *node, struct file *f, unsigned int cmd, + unsigned long arg) +{ + int retval = 0; + + /* Check for command validity */ + if (_IOC_TYPE(cmd) != IOCTL_BASE || _IOC_NR(cmd) > IOCTL_MAXNR) + return -ENOTTY; + + /* Check if the mode argument is sane */ + if (cmd == IOCTL_SET_MODE && (arg < SPI_MODE_0 || arg > SPI_MODE_3)) + return -EINVAL; + else if (cmd == IOCTL_SET_SIZE && (arg < 8 || arg > 16)) + return -EINVAL; + else if (cmd == IOCTL_SET_CHIP && arg > 3) + return -EINVAL; + + if (down_interruptible(&device->mutex)) + return -ERESTARTSYS; + + /* Commands that set the device configuration */ + if (cmd >= IOCTL_SET_MODE && cmd <= IOCTL_SET_BAUD) { + switch(cmd) { + case IOCTL_SET_MODE: + device->spi->mode = arg; + break; + case IOCTL_SET_SIZE: + device->spi->bits_per_word = arg; + break; + case IOCTL_SET_FILLER: + device->filler = arg; + break; + case IOCTL_SET_BAUD: + device->spi->max_speed_hz = arg; + break; + case IOCTL_SET_CHIP: + device->spi->chip_select = arg; + break; + default: + retval = -ENOTTY; + } + + /* Setup the SPI driver and channel */ + retval = spi_setup(device->spi); + } + /* Commands to query the device configuration */ + else + switch(cmd) { + case IOCTL_GET_MODE: + retval = put_user(device->spi->mode, (int *)arg); + break; + case IOCTL_GET_SIZE: + retval = put_user(device->spi->bits_per_word, + (int *)arg); + break; + case IOCTL_GET_FILLER: + retval = put_user(device->filler, (int *)arg); + break; + case IOCTL_GET_BAUD: + retval = put_user(device->spi->max_speed_hz, + (int *)arg); + break; + case IOCTL_GET_CHIP: + retval = put_user(device->spi->chip_select, (int *)arg); + break; + default: + retval = -ENOTTY; + } + + up(&device->mutex); + return retval; +} + +static struct file_operations fops = { + .owner = THIS_MODULE, + .read = scspi_read, + .write = scspi_write, + .open = scspi_open, + .release = scspi_release, + .ioctl = scspi_ioctl, +}; + +static struct spi_driver scspi_driver = { + .probe = scspi_probe, + .remove = __devexit_p(scspi_remove), + .driver = { + .name = "scspi", + } +}; + +static int __init scspi_load(void) +{ + int retval; + + device = kzalloc(sizeof(struct scspi_device), GFP_KERNEL); + if (!device) + return -ENOMEM; + + init_MUTEX(&device->mutex); + device->filler = FILLER; + + /* Major/minor number allocation */ + retval = alloc_chrdev_region(&device->number, 0, 1, "scspi"); + if (retval < 0) + goto alloc_chrdev_failed; + printk(KERN_DEBUG "scspi: 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 */ + retval = cdev_add(device->khandle, device->number, 1); + if (retval < 0) + goto cdev_add_failed; + + /* Registration of the driver with the linux device model */ + retval = spi_register_driver(&scspi_driver); + if (retval < 0) + 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: + printk(KERN_DEBUG "scspi: driver initialized\n"); + return 0; +} + +static void __exit scspi_unload(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); + printk(KERN_DEBUG "scspi: driver unloaded\n"); +} + +module_init(scspi_load); +module_exit(scspi_unload); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tasos Parisinos @ Sciensis Advanced Technology Systems"); +MODULE_DESCRIPTION("SPI protocol driver to create networks of spi interfaces"); + diff -uprN -X linux.orig/Documentation/dontdiff \ linux.orig/include/linux/Kbuild linux/include/linux/Kbuild --- linux.orig/include/linux/Kbuild 2007-02-04 20:44:54.000000000 +0200 +++ linux/include/linux/Kbuild 2007-04-17 10:57:24.000000000 +0300 @@ -11,6 +11,7 @@ header-y += netfilter_arp/ header-y += netfilter_bridge/ header-y += netfilter_ipv4/ header-y += netfilter_ipv6/ +header-y += spi/ header-y += affs_hardblocks.h header-y += aio_abi.h diff -uprN -X linux.orig/Documentation/dontdiff \ linux.orig/include/linux/spi/Kbuild linux/include/linux/spi/Kbuild --- linux.orig/include/linux/spi/Kbuild 1970-01-01 02:00:00.000000000 +0200 +++ linux/include/linux/spi/Kbuild 2007-04-17 10:59:51.000000000 +0300 @@ -0,0 +1 @@ +header-y += scspi.h diff -uprN -X linux.orig/Documentation/dontdiff \ linux.orig/include/linux/spi/scspi.h linux/include/linux/spi/scspi.h --- linux.orig/include/linux/spi/scspi.h 1970-01-01 02:00:00.000000000 +0200 +++ linux/include/linux/spi/scspi.h 2007-04-17 11:03:01.000000000 +0300 @@ -0,0 +1,28 @@ +#ifndef __SCSPI_H +#define __SCSPI_H + +#include + +#define SCSPI_IOCTL_BASE 0xF5 +#define SCSPI_CPHA 1 /* Clock phase */ +#define SCSPI_CPOL 2 /* Clock polarity */ +#define SCSPI_MODE_0 (0 | 0) +#define SCSPI_MODE_1 (0 | SCSPI_CPHA) +#define SCSPI_MODE_2 (SCSPI_CPOL | 0) +#define SCSPI_MODE_3 (SCSPI_CPOL | SCSPI_CPHA) + +#define SCSPI_IOR(nr, type) _IOR(SCSPI_IOCTL_BASE, nr, type) +#define SCSPI_IOW(nr, type) _IOW(SCSPI_IOCTL_BASE, nr, type) + +#define SCSPI_IOCTL_SET_MODE SCSPI_IOW(1, int) +#define SCSPI_IOCTL_SET_SIZE SCSPI_IOW(2, int) +#define SCSPI_IOCTL_SET_FILLER SCSPI_IOW(3, int) +#define SCSPI_IOCTL_SET_BAUD SCSPI_IOW(4, int) +#define SCSPI_IOCTL_SET_CHIP SCSPI_IOW(5, int) +#define SCSPI_IOCTL_GET_MODE SCSPI_IOR(6, int) +#define SCSPI_IOCTL_GET_SIZE SCSPI_IOR(7, int) +#define SCSPI_IOCTL_GET_FILLER SCSPI_IOR(8, int) +#define SCSPI_IOCTL_GET_BAUD SCSPI_IOR(9, int) +#define SCSPI_IOCTL_GET_CHIP SCSPI_IOR(10, int) + +#endif