Patch to add support for SPI busses. SPI bus master drivers and SPI slave drivers register with the SPI infrastructure.
Signed-off-by: Grant Likely <grant.likely at gdcanada.com> diff -ruNp linux/drivers/Kconfig linux-spi/drivers/Kconfig --- linux/drivers/Kconfig 2005-06-17 15:48:29.000000000 -0400 +++ linux-spi/drivers/Kconfig 2005-07-22 17:08:00.000000000 -0400 @@ -58,4 +58,6 @@ source "drivers/mmc/Kconfig" source "drivers/infiniband/Kconfig" +source "drivers/spi/Kconfig" + endmenu diff -ruNp linux/drivers/Makefile linux-spi/drivers/Makefile --- linux/drivers/Makefile 2005-06-17 15:48:29.000000000 -0400 +++ linux-spi/drivers/Makefile 2005-07-22 17:08:00.000000000 -0400 @@ -61,6 +61,7 @@ obj-$(CONFIG_EISA) += eisa/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_MMC) += mmc/ obj-$(CONFIG_INFINIBAND) += infiniband/ +obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_BLK_DEV_SGIIOC4) += sn/ obj-y += firmware/ obj-$(CONFIG_CRYPTO) += crypto/ diff -ruNp linux/drivers/spi/Kconfig linux-spi/drivers/spi/Kconfig --- linux/drivers/spi/Kconfig 1969-12-31 19:00:00.000000000 -0500 +++ linux-spi/drivers/spi/Kconfig 2005-07-22 17:08:00.000000000 -0400 @@ -0,0 +1,27 @@ +# +# SPI bus configuration +# + +menu "SPI support" + +config SPI + tristate "SPI support" + ---help--- + SPI is a serial bus protocol for connecting between ICs. SPI + support requires two components; a bus driver plus drivers for + each SPI slave device. + + Enabling SPI support will only cause SPI device drivers to be compiled into the kernel. You also need to make sure the platform setup code + takes care of mapping SPI slaves onto each SPI bus. + + Typically you will only need this for embedded systems. + Say N if unsure. + +comment "SPI Bus Drivers" + depends on SPI + +comment "SPI slaves" + depends on SPI + +endmenu + diff -ruNp linux/drivers/spi/Makefile linux-spi/drivers/spi/Makefile --- linux/drivers/spi/Makefile 1969-12-31 19:00:00.000000000 -0500 +++ linux-spi/drivers/spi/Makefile 2005-07-22 17:08:00.000000000 -0400 @@ -0,0 +1,5 @@ +# +# Makefile for the spi core. +# + +obj-$(CONFIG_SPI) += spi-core.o diff -ruNp linux/drivers/spi/spi-core.c linux-spi/drivers/spi/spi-core.c --- linux/drivers/spi/spi-core.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-spi/drivers/spi/spi-core.c 2005-07-22 17:08:00.000000000 -0400 @@ -0,0 +1,156 @@ +/* + * drivers/spi/spi-core.c + * + * Core Serial Peripheral Interface (SPI) bus infrastructure + * + * Adds support for SPI busses. SPI master devices and SPI device drivers + * register with spi core. SPI slave devices get attached to SPI masters + * and are matched with an SPI device driver using the facillities of the + * linux device model. + * + * SPI is oriented around 'transfers' initiated by the SPI master. A transfer + * begins when the master asserts the 'slave select (SS)' signal. It then + * clocks out data one bit at a time on the "Master Out/Slave In (MOSI)" line + * and samples one bit at a time on the "Master In/Slave Out (MISO)" line. + * Clocking out and sampling are syncronized with the clock signal which is + * driven by the master. Exactly the same amount of data is transmitted as + * is received for each transfer. The transfer if finished when the master + * deasserts the SS signal. + * + * SPI bus drivers provide a 'transfer' method which accepts an input buffer, + * an output buffer and a count. Slave device drivers use the transfer method + * to communicate with the slave device. It is up to the slave device driver + * to decide what to do with the transfered data. + * + * This infrastructure is for SPI master devices only. Linux cannot be an + * SPI slave with this module. Theoretically multi-master busses will work + * as long as the other master doesn't try to use us as a slave + * + * Maintainer : Grant Likely <glikely at gmail.com> + * + * This file is in the public domain. + * + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/fs.h> +#include <linux/spi.h> +#include <asm/uaccess.h> + +MODULE_AUTHOR("Grant Likely <glikely at gmail.com>"); +MODULE_DESCRIPTION("Freescale MPC52xx PSC in SPI mode"); +MODULE_LICENSE("Dual BSD/GPL"); + +/* Simple enumeration scheme for assigning bus ids */ +static int spi_next_bus_id = 0; + +/* Forward Declarations */ +static int spi_match (struct device *dev, struct device_driver *drv); +static void spi_bus_release(struct device *dev); + +/* Linux device model stuff (for registering a new bus type) */ +struct bus_type spi_bus_type = { + .name = "spi", + .match = spi_match, +}; + +static struct sysfs_ops spi_driver_sysfs_ops = { +}; + +static struct kobj_type spi_driver_kobj_type = { + .sysfs_ops = &spi_driver_sysfs_ops, +}; + +/* Called by device model to match devices to device drivers + * + * Devices are matched to devices based on the name fields in the spi_dev + * and device_driver structures. If the names match, then the device and + * driver can possibly be connected + */ +static int spi_match (struct device *dev, struct device_driver *drv) +{ + struct spi_device *spi_device = to_spi_dev(dev); + return !strncmp(spi_device->name, drv->name, strlen(drv->name)); +} + +static void spi_bus_release(struct device *dev) +{ +} + +/* Initialize common SPI bus fields before registering the bus device with the + * device model + */ +int spi_bus_register(struct spi_bus *spi) +{ + snprintf(spi->dev.bus_id, BUS_ID_SIZE, "spi%i", spi_next_bus_id++); + spi->dev.release = spi_bus_release; + + return device_register(&spi->dev); +} + +void spi_bus_unregister(struct spi_bus *spi) +{ + device_unregister(&spi->dev); +} + +/* Helper function for attaching SPI slave devices to an SPI bus. Slave + * devices should get matched to slave device drivers + */ +int spi_device_create(struct spi_bus *bus, char *name, int id) +{ + struct spi_device *dev; + + dev = kmalloc(sizeof (struct spi_device), GFP_KERNEL); + if (!dev) { + return -ENOMEM; + } + memset(dev, 0, sizeof(struct spi_device)); + + strlcpy(dev->name, name, SPI_NAME_SIZE); + dev->id = id; + snprintf(dev->dev.bus_id, BUS_ID_SIZE, "%s.%i", name, id); + dev->dev.parent = &bus->dev; + dev->dev.bus = &spi_bus_type; + + return device_register(&dev->dev); +} + +/* Register an SPI slave device driver with the SPI infrastructure */ +int spi_driver_register(struct spi_driver *drv) +{ + int err; + + drv->driver.name = drv->name; + drv->driver.bus = &spi_bus_type; + drv->driver.kobj.ktype = &spi_driver_kobj_type; + err = driver_register(&drv->driver); + return err; +} + +void spi_driver_unregister(struct spi_driver *drv) +{ + driver_unregister(&drv->driver); +} + +static int __init spi_init(void) +{ + printk(KERN_INFO "spi-core: initializing\n"); + + return bus_register(&spi_bus_type); +} + +static void __exit spi_exit(void) +{ + bus_unregister(&spi_bus_type); +} + +module_init(spi_init); +module_exit(spi_exit); +EXPORT_SYMBOL(spi_bus_register); +EXPORT_SYMBOL(spi_bus_unregister); +EXPORT_SYMBOL(spi_device_create); +EXPORT_SYMBOL(spi_driver_register); +EXPORT_SYMBOL(spi_driver_unregister); + diff -ruNp linux/include/linux/spi.h linux-spi/include/linux/spi.h --- linux/include/linux/spi.h 1969-12-31 19:00:00.000000000 -0500 +++ linux-spi/include/linux/spi.h 2005-07-22 17:08:00.000000000 -0400 @@ -0,0 +1,72 @@ +/* + * drivers/spi/spi.h + * + * Core Serial Peripheral Interface (SPI) bus infrastructure + * + * Adds support for SPI busses. SPI master devices and SPI device drivers + * register with spi core. SPI slave devices get attached to SPI masters + * and are matched with an SPI device driver using the facillities of the + * linux device model. + * + * SPI is oriented around 'transfers' initiated by the SPI master. A transfer + * begins when the master asserts the 'slave select (SS)' signal. It then + * clocks out data one bit at a time on the "Master Out/Slave In (MOSI)" line + * and samples one bit at a time on the "Master In/Slave Out (MISO)" line. + * Clocking out and sampling are syncronized with the clock signal which is + * driven by the master. Exactly the same amount of data is transmitted as + * is received for each transfer. The transfer if finished when the master + * deasserts the SS signal. + * + * SPI bus drivers provide a 'transfer' method which accepts an input buffer, + * an output buffer and a count. Slave device drivers use the transfer method + * to communicate with the slave device. It is up to the slave device driver + * to decide what to do with the transfered data. + * + * This infrastructure is for SPI master devices only. Linux cannot be an + * SPI slave with this module. Multi-master SPI busses aren't supported + * either. + * + * Maintainer : Grant Likely <glikely at gmail.com> + * + * This file is in the public domain + */ + +struct spi_bus { + struct spi_bus_ops *ops; + struct device dev; + void *input_buff; + int input_len; +}; +#define to_spi_bus(d) container_of(d, struct spi_bus, dev); + +#define SPI_CLKEDGE_RISING 0 +#define SPI_CLKEDGE_FALLING 1 +struct spi_bus_ops { + int (*transfer) (struct spi_bus *bus, int id, int clkedge, + uint8_t *in, const uint8_t *out, size_t count); +}; + +struct spi_driver { + char *name; + struct module *module; + struct device_driver driver; +}; + +#define SPI_NAME_SIZE KOBJ_NAME_LEN +struct spi_device { + char name[SPI_NAME_SIZE]; + int id; + struct spi_driver *driver; + struct device dev; +}; +#define to_spi_dev(d) container_of(d, struct spi_device, dev); + + +extern int spi_device_create(struct spi_bus *bus, char *name, int id); + +/* Interface functions for registering and unregistering SPI busses */ +extern int spi_bus_register(struct spi_bus *bus); +extern void spi_bus_unregister(struct spi_bus *bus); + +extern int spi_driver_register(struct spi_driver *driver); +extern void spi_driver_unregister(struct spi_driver *driver);