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);

Reply via email to