summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorAnton Altaparmakov <aia21@cantab.net>2006-01-19 16:39:33 +0000
committerAnton Altaparmakov <aia21@cantab.net>2006-01-19 16:39:33 +0000
commit944d79559d154c12becde0dab327016cf438f46c (patch)
tree50c101806f4d3b6585222dda060559eb4f3e005a /drivers/spi
parentd087e4bdd24ebe3ae3d0b265b6573ec901af4b4b (diff)
parent0f36b018b2e314d45af86449f1a97facb1fbe300 (diff)
Merge branch 'master' of /usr/src/ntfs-2.6/
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Kconfig109
-rw-r--r--drivers/spi/Makefile25
-rw-r--r--drivers/spi/spi.c642
-rw-r--r--drivers/spi/spi_bitbang.c472
-rw-r--r--drivers/spi/spi_butterfly.c423
5 files changed, 1671 insertions, 0 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
new file mode 100644
index 00000000000..b77dbd63e59
--- /dev/null
+++ b/drivers/spi/Kconfig
@@ -0,0 +1,109 @@
+#
+# SPI driver configuration
+#
+# NOTE: the reason this doesn't show SPI slave support is mostly that
+# nobody's needed a slave side API yet. The master-role API is not
+# fully appropriate there, so it'd need some thought to do well.
+#
+menu "SPI support"
+
+config SPI
+ bool "SPI support"
+ help
+ The "Serial Peripheral Interface" is a low level synchronous
+ protocol. Chips that support SPI can have data transfer rates
+ up to several tens of Mbit/sec. Chips are addressed with a
+ controller and a chipselect. Most SPI slaves don't support
+ dynamic device discovery; some are even write-only or read-only.
+
+ SPI is widely used by microcontollers to talk with sensors,
+ eeprom and flash memory, codecs and various other controller
+ chips, analog to digital (and d-to-a) converters, and more.
+ MMC and SD cards can be accessed using SPI protocol; and for
+ DataFlash cards used in MMC sockets, SPI must always be used.
+
+ SPI is one of a family of similar protocols using a four wire
+ interface (select, clock, data in, data out) including Microwire
+ (half duplex), SSP, SSI, and PSP. This driver framework should
+ work with most such devices and controllers.
+
+config SPI_DEBUG
+ boolean "Debug support for SPI drivers"
+ depends on SPI && DEBUG_KERNEL
+ help
+ Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
+ sysfs, and debugfs support in SPI controller and protocol drivers.
+
+#
+# MASTER side ... talking to discrete SPI slave chips including microcontrollers
+#
+
+config SPI_MASTER
+# boolean "SPI Master Support"
+ boolean
+ default SPI
+ help
+ If your system has an master-capable SPI controller (which
+ provides the clock and chipselect), you can enable that
+ controller and the protocol drivers for the SPI slave chips
+ that are connected.
+
+comment "SPI Master Controller Drivers"
+ depends on SPI_MASTER
+
+config SPI_BITBANG
+ tristate "Bitbanging SPI master"
+ depends on SPI_MASTER && EXPERIMENTAL
+ help
+ With a few GPIO pins, your system can bitbang the SPI protocol.
+ Select this to get SPI support through I/O pins (GPIO, parallel
+ port, etc). Or, some systems' SPI master controller drivers use
+ this code to manage the per-word or per-transfer accesses to the
+ hardware shift registers.
+
+ This is library code, and is automatically selected by drivers that
+ need it. You only need to select this explicitly to support driver
+ modules that aren't part of this kernel tree.
+
+config SPI_BUTTERFLY
+ tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
+ depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This uses a custom parallel port cable to connect to an AVR
+ Butterfly <http://www.atmel.com/products/avr/butterfly>, an
+ inexpensive battery powered microcontroller evaluation board.
+ This same cable can be used to flash new firmware.
+
+config SPI_BUTTERFLY
+ tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)"
+ depends on SPI_MASTER && PARPORT && EXPERIMENTAL
+ select SPI_BITBANG
+ help
+ This uses a custom parallel port cable to connect to an AVR
+ Butterfly <http://www.atmel.com/products/avr/butterfly>, an
+ inexpensive battery powered microcontroller evaluation board.
+ This same cable can be used to flash new firmware.
+
+#
+# Add new SPI master controllers in alphabetical order above this line
+#
+
+
+#
+# There are lots of SPI device types, with sensors and memory
+# being probably the most widely used ones.
+#
+comment "SPI Protocol Masters"
+ depends on SPI_MASTER
+
+
+#
+# Add new SPI protocol masters in alphabetical order above this line
+#
+
+
+# (slave support would go here)
+
+endmenu # "SPI support"
+
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
new file mode 100644
index 00000000000..c2c87e845ab
--- /dev/null
+++ b/drivers/spi/Makefile
@@ -0,0 +1,25 @@
+#
+# Makefile for kernel SPI drivers.
+#
+
+ifeq ($(CONFIG_SPI_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
+# small core, mostly translating board-specific
+# config declarations into driver model code
+obj-$(CONFIG_SPI_MASTER) += spi.o
+
+# SPI master controller drivers (bus)
+obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
+obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+# ... add above this line ...
+
+# SPI protocol drivers (device/link on bus)
+# ... add above this line ...
+
+# SPI slave controller drivers (upstream link)
+# ... add above this line ...
+
+# SPI slave drivers (protocol for that link)
+# ... add above this line ...
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
new file mode 100644
index 00000000000..791c4dc550a
--- /dev/null
+++ b/drivers/spi/spi.c
@@ -0,0 +1,642 @@
+/*
+ * spi.c - SPI init/core code
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/cache.h>
+#include <linux/spi/spi.h>
+
+
+/* SPI bustype and spi_master class are registered after board init code
+ * provides the SPI device tables, ensuring that both are present by the
+ * time controller driver registration causes spi_devices to "enumerate".
+ */
+static void spidev_release(struct device *dev)
+{
+ const struct spi_device *spi = to_spi_device(dev);
+
+ /* spi masters may cleanup for released devices */
+ if (spi->master->cleanup)
+ spi->master->cleanup(spi);
+
+ spi_master_put(spi->master);
+ kfree(dev);
+}
+
+static ssize_t
+modalias_show(struct device *dev, struct device_attribute *a, char *buf)
+{
+ const struct spi_device *spi = to_spi_device(dev);
+
+ return snprintf(buf, BUS_ID_SIZE + 1, "%s\n", spi->modalias);
+}
+
+static struct device_attribute spi_dev_attrs[] = {
+ __ATTR_RO(modalias),
+ __ATTR_NULL,
+};
+
+/* modalias support makes "modprobe $MODALIAS" new-style hotplug work,
+ * and the sysfs version makes coldplug work too.
+ */
+
+static int spi_match_device(struct device *dev, struct device_driver *drv)
+{
+ const struct spi_device *spi = to_spi_device(dev);
+
+ return strncmp(spi->modalias, drv->name, BUS_ID_SIZE) == 0;
+}
+
+static int spi_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ const struct spi_device *spi = to_spi_device(dev);
+
+ envp[0] = buffer;
+ snprintf(buffer, buffer_size, "MODALIAS=%s", spi->modalias);
+ envp[1] = NULL;
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/*
+ * NOTE: the suspend() method for an spi_master controller driver
+ * should verify that all its child devices are marked as suspended;
+ * suspend requests delivered through sysfs power/state files don't
+ * enforce such constraints.
+ */
+static int spi_suspend(struct device *dev, pm_message_t message)
+{
+ int value;
+ struct spi_driver *drv = to_spi_driver(dev->driver);
+
+ if (!drv->suspend)
+ return 0;
+
+ /* suspend will stop irqs and dma; no more i/o */
+ value = drv->suspend(to_spi_device(dev), message);
+ if (value == 0)
+ dev->power.power_state = message;
+ return value;
+}
+
+static int spi_resume(struct device *dev)
+{
+ int value;
+ struct spi_driver *drv = to_spi_driver(dev->driver);
+
+ if (!drv->resume)
+ return 0;
+
+ /* resume may restart the i/o queue */
+ value = drv->resume(to_spi_device(dev));
+ if (value == 0)
+ dev->power.power_state = PMSG_ON;
+ return value;
+}
+
+#else
+#define spi_suspend NULL
+#define spi_resume NULL
+#endif
+
+struct bus_type spi_bus_type = {
+ .name = "spi",
+ .dev_attrs = spi_dev_attrs,
+ .match = spi_match_device,
+ .uevent = spi_uevent,
+ .suspend = spi_suspend,
+ .resume = spi_resume,
+};
+EXPORT_SYMBOL_GPL(spi_bus_type);
+
+
+static int spi_drv_probe(struct device *dev)
+{
+ const struct spi_driver *sdrv = to_spi_driver(dev->driver);
+
+ return sdrv->probe(to_spi_device(dev));
+}
+
+static int spi_drv_remove(struct device *dev)
+{
+ const struct spi_driver *sdrv = to_spi_driver(dev->driver);
+
+ return sdrv->remove(to_spi_device(dev));
+}
+
+static void spi_drv_shutdown(struct device *dev)
+{
+ const struct spi_driver *sdrv = to_spi_driver(dev->driver);
+
+ sdrv->shutdown(to_spi_device(dev));
+}
+
+int spi_register_driver(struct spi_driver *sdrv)
+{
+ sdrv->driver.bus = &spi_bus_type;
+ if (sdrv->probe)
+ sdrv->driver.probe = spi_drv_probe;
+ if (sdrv->remove)
+ sdrv->driver.remove = spi_drv_remove;
+ if (sdrv->shutdown)
+ sdrv->driver.shutdown = spi_drv_shutdown;
+ return driver_register(&sdrv->driver);
+}
+EXPORT_SYMBOL_GPL(spi_register_driver);
+
+/*-------------------------------------------------------------------------*/
+
+/* SPI devices should normally not be created by SPI device drivers; that
+ * would make them board-specific. Similarly with SPI master drivers.
+ * Device registration normally goes into like arch/.../mach.../board-YYY.c
+ * with other readonly (flashable) information about mainboard devices.
+ */
+
+struct boardinfo {
+ struct list_head list;
+ unsigned n_board_info;
+ struct spi_board_info board_info[0];
+};
+
+static LIST_HEAD(board_list);
+static DECLARE_MUTEX(board_lock);
+
+
+/* On typical mainboards, this is purely internal; and it's not needed
+ * after board init creates the hard-wired devices. Some development
+ * platforms may not be able to use spi_register_board_info though, and
+ * this is exported so that for example a USB or parport based adapter
+ * driver could add devices (which it would learn about out-of-band).
+ */
+struct spi_device *__init_or_module
+spi_new_device(struct spi_master *master, struct spi_board_info *chip)
+{
+ struct spi_device *proxy;
+ struct device *dev = master->cdev.dev;
+ int status;
+
+ /* NOTE: caller did any chip->bus_num checks necessary */
+
+ if (!spi_master_get(master))
+ return NULL;
+
+ proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
+ if (!proxy) {
+ dev_err(dev, "can't alloc dev for cs%d\n",
+ chip->chip_select);
+ goto fail;
+ }
+ proxy->master = master;
+ proxy->chip_select = chip->chip_select;
+ proxy->max_speed_hz = chip->max_speed_hz;
+ proxy->irq = chip->irq;
+ proxy->modalias = chip->modalias;
+
+ snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
+ "%s.%u", master->cdev.class_id,
+ chip->chip_select);
+ proxy->dev.parent = dev;
+ proxy->dev.bus = &spi_bus_type;
+ proxy->dev.platform_data = (void *) chip->platform_data;
+ proxy->controller_data = chip->controller_data;
+ proxy->controller_state = NULL;
+ proxy->dev.release = spidev_release;
+
+ /* drivers may modify this default i/o setup */
+ status = master->setup(proxy);
+ if (status < 0) {
+ dev_dbg(dev, "can't %s %s, status %d\n",
+ "setup", proxy->dev.bus_id, status);
+ goto fail;
+ }
+
+ /* driver core catches callers that misbehave by defining
+ * devices that already exist.
+ */
+ status = device_register(&proxy->dev);
+ if (status < 0) {
+ dev_dbg(dev, "can't %s %s, status %d\n",
+ "add", proxy->dev.bus_id, status);
+ goto fail;
+ }
+ dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
+ return proxy;
+
+fail:
+ spi_master_put(master);
+ kfree(proxy);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(spi_new_device);
+
+/*
+ * Board-specific early init code calls this (probably during arch_initcall)
+ * with segments of the SPI device table. Any device nodes are created later,
+ * after the relevant parent SPI controller (bus_num) is defined. We keep
+ * this table of devices forever, so that reloading a controller driver will
+ * not make Linux forget about these hard-wired devices.
+ *
+ * Other code can also call this, e.g. a particular add-on board might provide
+ * SPI devices through its expansion connector, so code initializing that board
+ * would naturally declare its SPI devices.
+ *
+ * The board info passed can safely be __initdata ... but be careful of
+ * any embedded pointers (platform_data, etc), they're copied as-is.
+ */
+int __init
+spi_register_board_info(struct spi_board_info const *info, unsigned n)
+{
+ struct boardinfo *bi;
+
+ bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+ if (!bi)
+ return -ENOMEM;
+ bi->n_board_info = n;
+ memcpy(bi->board_info, info, n * sizeof *info);
+
+ down(&board_lock);
+ list_add_tail(&bi->list, &board_list);
+ up(&board_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_register_board_info);
+
+/* FIXME someone should add support for a __setup("spi", ...) that
+ * creates board info from kernel command lines
+ */
+
+static void __init_or_module
+scan_boardinfo(struct spi_master *master)
+{
+ struct boardinfo *bi;
+ struct device *dev = master->cdev.dev;
+
+ down(&board_lock);
+ list_for_each_entry(bi, &board_list, list) {
+ struct spi_board_info *chip = bi->board_info;
+ unsigned n;
+
+ for (n = bi->n_board_info; n > 0; n--, chip++) {
+ if (chip->bus_num != master->bus_num)
+ continue;
+ /* some controllers only have one chip, so they
+ * might not use chipselects. otherwise, the
+ * chipselects are numbered 0..max.
+ */
+ if (chip->chip_select >= master->num_chipselect
+ && master->num_chipselect) {
+ dev_dbg(dev, "cs%d > max %d\n",
+ chip->chip_select,
+ master->num_chipselect);
+ continue;
+ }
+ (void) spi_new_device(master, chip);
+ }
+ }
+ up(&board_lock);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void spi_master_release(struct class_device *cdev)
+{
+ struct spi_master *master;
+
+ master = container_of(cdev, struct spi_master, cdev);
+ kfree(master);
+}
+
+static struct class spi_master_class = {
+ .name = "spi_master",
+ .owner = THIS_MODULE,
+ .release = spi_master_release,
+};
+
+
+/**
+ * spi_alloc_master - allocate SPI master controller
+ * @dev: the controller, possibly using the platform_bus
+ * @size: how much driver-private data to preallocate; the pointer to this
+ * memory is in the class_data field of the returned class_device,
+ * accessible with spi_master_get_devdata().
+ *
+ * This call is used only by SPI master controller drivers, which are the
+ * only ones directly touching chip registers. It's how they allocate
+ * an spi_master structure, prior to calling spi_add_master().
+ *
+ * This must be called from context that can sleep. It returns the SPI
+ * master structure on success, else NULL.
+ *
+ * The caller is responsible for assigning the bus number and initializing
+ * the master's methods before calling spi_add_master(); and (after errors
+ * adding the device) calling spi_master_put() to prevent a memory leak.
+ */
+struct spi_master * __init_or_module
+spi_alloc_master(struct device *dev, unsigned size)
+{
+ struct spi_master *master;
+
+ if (!dev)
+ return NULL;
+
+ master = kzalloc(size + sizeof *master, SLAB_KERNEL);
+ if (!master)
+ return NULL;
+
+ class_device_initialize(&master->cdev);
+ master->cdev.class = &spi_master_class;
+ master->cdev.dev = get_device(dev);
+ spi_master_set_devdata(master, &master[1]);
+
+ return master;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_master);
+
+/**
+ * spi_register_master - register SPI master controller
+ * @master: initialized master, originally from spi_alloc_master()
+ *
+ * SPI master controllers connect to their drivers using some non-SPI bus,
+ * such as the platform bus. The final stage of probe() in that code
+ * includes calling spi_register_master() to hook up to this SPI bus glue.
+ *
+ * SPI controllers use board specific (often SOC specific) bus numbers,
+ * and board-specific addressing for SPI devices combines those numbers
+ * with chip select numbers. Since SPI does not directly support dynamic
+ * device identification, boards need configuration tables telling which
+ * chip is at which address.
+ *
+ * This must be called from context that can sleep. It returns zero on
+ * success, else a negative error code (dropping the master's refcount).
+ * After a successful return, the caller is responsible for calling
+ * spi_unregister_master().
+ */
+int __init_or_module
+spi_register_master(struct spi_master *master)
+{
+ static atomic_t dyn_bus_id = ATOMIC_INIT(0);
+ struct device *dev = master->cdev.dev;
+ int status = -ENODEV;
+ int dynamic = 0;
+
+ if (!dev)
+ return -ENODEV;
+
+ /* convention: dynamically assigned bus IDs count down from the max */
+ if (master->bus_num == 0) {
+ master->bus_num = atomic_dec_return(&dyn_bus_id);
+ dynamic = 1;
+ }
+
+ /* register the device, then userspace will see it.
+ * registration fails if the bus ID is in use.
+ */
+ snprintf(master->cdev.class_id, sizeof master->cdev.class_id,
+ "spi%u", master->bus_num);
+ status = class_device_add(&master->cdev);
+ if (status < 0)
+ goto done;
+ dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
+ dynamic ? " (dynamic)" : "");
+
+ /* populate children from any spi device tables */
+ scan_boardinfo(master);
+ status = 0;
+done:
+ return status;
+}
+EXPORT_SYMBOL_GPL(spi_register_master);
+
+
+static int __unregister(struct device *dev, void *unused)
+{
+ /* note: before about 2.6.14-rc1 this would corrupt memory: */
+ spi_unregister_device(to_spi_device(dev));
+ return 0;
+}
+
+/**
+ * spi_unregister_master - unregister SPI master controller
+ * @master: the master being unregistered
+ *
+ * This call is used only by SPI master controller drivers, which are the
+ * only ones directly touching chip registers.
+ *
+ * This must be called from context that can sleep.
+ */
+void spi_unregister_master(struct spi_master *master)
+{
+ (void) device_for_each_child(master->cdev.dev, NULL, __unregister);
+ class_device_unregister(&master->cdev);
+ master->cdev.dev = NULL;
+}
+EXPORT_SYMBOL_GPL(spi_unregister_master);
+
+/**
+ * spi_busnum_to_master - look up master associated with bus_num
+ * @bus_num: the master's bus number
+ *
+ * This call may be used with devices that are registered after
+ * arch init time. It returns a refcounted pointer to the relevant
+ * spi_master (which the caller must release), or NULL if there is
+ * no such master registered.
+ */
+struct spi_master *spi_busnum_to_master(u16 bus_num)
+{
+ if (bus_num) {
+ char name[8];
+ struct kobject *bus;
+
+ snprintf(name, sizeof name, "spi%u", bus_num);
+ bus = kset_find_obj(&spi_master_class.subsys.kset, name);
+ if (bus)
+ return container_of(bus, struct spi_master, cdev.kobj);
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(spi_busnum_to_master);
+
+
+/*-------------------------------------------------------------------------*/
+
+static void spi_complete(void *arg)
+{
+ complete(arg);
+}
+
+/**
+ * spi_sync - blocking/synchronous SPI data transfers
+ * @spi: device with which data will be exchanged
+ * @message: describes the data transfers
+ *
+ * This call may only be used from a context that may sleep. The sleep
+ * is non-interruptible, and has no timeout. Low-overhead controller
+ * drivers may DMA directly into and out of the message buffers.
+ *
+ * Note that the SPI device's chip select is active during the message,
+ * and then is normally disabled between messages. Drivers for some
+ * frequently-used devices may want to minimize costs of selecting a chip,
+ * by leaving it selected in anticipation that the next message will go
+ * to the same chip. (That may increase power usage.)
+ *
+ * Also, the caller is guaranteeing that the memory associated with the
+ * message will not be freed before this call returns.
+ *
+ * The return value is a negative error code if the message could not be
+ * submitted, else zero. When the value is zero, then message->status is
+ * also defined: it's the completion code for the transfer, either zero
+ * or a negative error code from the controller driver.
+ */
+int spi_sync(struct spi_device *spi, struct spi_message *message)
+{
+ DECLARE_COMPLETION(done);
+ int status;
+
+ message->complete = spi_complete;
+ message->context = &done;
+ status = spi_async(spi, message);
+ if (status == 0)
+ wait_for_completion(&done);
+ message->context = NULL;
+ return status;
+}
+EXPORT_SYMBOL_GPL(spi_sync);
+
+#define SPI_BUFSIZ (SMP_CACHE_BYTES)
+
+static u8 *buf;
+
+/**
+ * spi_write_then_read - SPI synchronous write followed by read
+ * @spi: device with which data will be exchanged
+ * @txbuf: data to be written (need not be dma-safe)
+ * @n_tx: size of txbuf, in bytes
+ * @rxbuf: buffer into which data will be read
+ * @n_rx: size of rxbuf, in bytes (need not be dma-safe)
+ *
+ * This performs a half duplex MicroWire style transaction with the
+ * device, sending txbuf and then reading rxbuf. The return value
+ * is zero for success, else a negative errno status code.
+ * This call may only be used from a context that may sleep.
+ *
+ * Parameters to this routine are always copied using a small buffer;
+ * performance-sensitive or bulk transfer code should instead use
+ * spi_{async,sync}() calls with dma-safe buffers.
+ */
+int spi_write_then_read(struct spi_device *spi,
+ const u8 *txbuf, unsigned n_tx,
+ u8 *rxbuf, unsigned n_rx)
+{
+ static DECLARE_MUTEX(lock);
+
+ int status;
+ struct spi_message message;
+ struct spi_transfer x[2];
+ u8 *local_buf;
+
+ /* Use preallocated DMA-safe buffer. We can't avoid copying here,
+ * (as a pure convenience thing), but we can keep heap costs
+ * out of the hot path ...
+ */
+ if ((n_tx + n_rx) > SPI_BUFSIZ)
+ return -EINVAL;
+
+ spi_message_init(&message);
+ memset(x, 0, sizeof x);
+ if (n_tx) {
+ x[0].len = n_tx;
+ spi_message_add_tail(&x[0], &message);
+ }
+ if (n_rx) {
+ x[1].len = n_rx;
+ spi_message_add_tail(&x[1], &message);
+ }
+
+ /* ... unless someone else is using the pre-allocated buffer */
+ if (down_trylock(&lock)) {
+ local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
+ if (!local_buf)
+ return -ENOMEM;
+ } else
+ local_buf = buf;
+
+ memcpy(local_buf, txbuf, n_tx);
+ x[0].tx_buf = local_buf;
+ x[1].rx_buf = local_buf + n_tx;
+
+ /* do the i/o */
+ status = spi_sync(spi, &message);
+ if (status == 0) {
+ memcpy(rxbuf, x[1].rx_buf, n_rx);
+ status = message.status;
+ }
+
+ if (x[0].tx_buf == buf)
+ up(&lock);
+ else
+ kfree(local_buf);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(spi_write_then_read);
+
+/*-------------------------------------------------------------------------*/
+
+static int __init spi_init(void)
+{
+ int status;
+
+ buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
+ if (!buf) {
+ status = -ENOMEM;
+ goto err0;
+ }
+
+ status = bus_register(&spi_bus_type);
+ if (status < 0)
+ goto err1;
+
+ status = class_register(&spi_master_class);
+ if (status < 0)
+ goto err2;
+ return 0;
+
+err2:
+ bus_unregister(&spi_bus_type);
+err1:
+ kfree(buf);
+ buf = NULL;
+err0:
+ return status;
+}
+
+/* board_info is normally registered in arch_initcall(),
+ * but even essential drivers wait till later
+ *
+ * REVISIT only boardinfo really needs static linking. the rest (device and
+ * driver registration) _could_ be dynamically linked (modular) ... costs
+ * include needing to have boardinfo data structures be much more public.
+ */
+subsys_initcall(spi_init);
+
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
new file mode 100644
index 00000000000..f037e559326
--- /dev/null
+++ b/drivers/spi/spi_bitbang.c
@@ -0,0 +1,472 @@
+/*
+ * spi_bitbang.c - polling/bitbanging SPI master controller driver utilities
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * FIRST PART (OPTIONAL): word-at-a-time spi_transfer support.
+ * Use this for GPIO or shift-register level hardware APIs.
+ *
+ * spi_bitbang_cs is in spi_device->controller_state, which is unavailable
+ * to glue code. These bitbang setup() and cleanup() routines are always
+ * used, though maybe they're called from controller-aware code.
+ *
+ * chipselect() and friends may use use spi_device->controller_data and
+ * controller registers as appropriate.
+ *
+ *
+ * NOTE: SPI controller pins can often be used as GPIO pins instead,
+ * which means you could use a bitbang driver either to get hardware
+ * working quickly, or testing for differences that aren't speed related.
+ */
+
+struct spi_bitbang_cs {
+ unsigned nsecs; /* (clock cycle time)/2 */
+ u32 (*txrx_word)(struct spi_device *spi, unsigned nsecs,
+ u32 word, u8 bits);
+ unsigned (*txrx_bufs)(struct spi_device *,
+ u32 (*txrx_word)(
+ struct spi_device *spi,
+ unsigned nsecs,
+ u32 word, u8 bits),
+ unsigned, struct spi_transfer *);
+};
+
+static unsigned bitbang_txrx_8(
+ struct spi_device *spi,
+ u32 (*txrx_word)(struct spi_device *spi,
+ unsigned nsecs,
+ u32 word, u8 bits),
+ unsigned ns,
+ struct spi_transfer *t
+) {
+ unsigned bits = spi->bits_per_word;
+ unsigned count = t->len;
+ const u8 *tx = t->tx_buf;
+ u8 *rx = t->rx_buf;
+
+ while (likely(count > 0)) {
+ u8 word = 0;
+
+ if (tx)
+ word = *tx++;
+ word = txrx_word(spi, ns, word, bits);
+ if (rx)
+ *rx++ = word;
+ count -= 1;
+ }
+ return t->len - count;
+}
+
+static unsigned bitbang_txrx_16(
+ struct spi_device *spi,
+ u32 (*txrx_word)(struct spi_device *spi,
+ unsigned nsecs,
+ u32 word, u8 bits),
+ unsigned ns,
+ struct spi_transfer *t
+) {
+ unsigned bits = spi->bits_per_word;
+ unsigned count = t->len;
+ const u16 *tx = t->tx_buf;
+ u16 *rx = t->rx_buf;
+
+ while (likely(count > 1)) {
+ u16 word = 0;
+
+ if (tx)
+ word = *tx++;
+ word = txrx_word(spi, ns, word, bits);
+ if (rx)
+ *rx++ = word;
+ count -= 2;
+ }
+ return t->len - count;
+}
+
+static unsigned bitbang_txrx_32(
+ struct spi_device *spi,
+ u32 (*txrx_word)(struct spi_device *spi,
+ unsigned nsecs,
+ u32 word, u8 bits),
+ unsigned ns,
+ struct spi_transfer *t
+) {
+ unsigned bits = spi->bits_per_word;
+ unsigned count = t->len;
+ const u32 *tx = t->tx_buf;
+ u32 *rx = t->rx_buf;
+
+ while (likely(count > 3)) {
+ u32 word = 0;
+
+ if (tx)
+ word = *tx++;
+ word = txrx_word(spi, ns, word, bits);
+ if (rx)
+ *rx++ = word;
+ count -= 4;
+ }
+ return t->len - count;
+}
+
+/**
+ * spi_bitbang_setup - default setup for per-word I/O loops
+ */
+int spi_bitbang_setup(struct spi_device *spi)
+{
+ struct spi_bitbang_cs *cs = spi->controller_state;
+ struct spi_bitbang *bitbang;
+
+ if (!spi->max_speed_hz)
+ return -EINVAL;
+
+ if (!cs) {
+ cs = kzalloc(sizeof *cs, SLAB_KERNEL);
+ if (!cs)
+ return -ENOMEM;
+ spi->controller_state = cs;
+ }
+ bitbang = spi_master_get_devdata(spi->master);
+
+ if (!spi->bits_per_word)
+ spi->bits_per_word = 8;
+
+ /* spi_transfer level calls that work per-word */
+ if (spi->bits_per_word <= 8)
+ cs->txrx_bufs = bitbang_txrx_8;
+ else if (spi->bits_per_word <= 16)
+ cs->txrx_bufs = bitbang_txrx_16;
+ else if (spi->bits_per_word <= 32)
+ cs->txrx_bufs = bitbang_txrx_32;
+ else
+ return -EINVAL;
+
+ /* per-word shift register access, in hardware or bitbanging */
+ cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
+ if (!cs->txrx_word)
+ return -EINVAL;
+
+ /* nsecs = (clock period)/2 */
+ cs->nsecs = (1000000000/2) / (spi->max_speed_hz);
+ if (cs->nsecs > MAX_UDELAY_MS * 1000)
+ return -EINVAL;
+
+ dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
+ __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
+ spi->bits_per_word, 2 * cs->nsecs);
+
+ /* NOTE we _need_ to call chipselect() early, ideally with adapter
+ * setup, unless the hardware defaults cooperate to avoid confusion
+ * between normal (active low) and inverted chipselects.
+ */
+
+ /* deselect chip (low or high) */
+ spin_lock(&bitbang->lock);
+ if (!bitbang->busy) {
+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+ ndelay(cs->nsecs);
+ }
+ spin_unlock(&bitbang->lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_setup);
+
+/**
+ * spi_bitbang_cleanup - default cleanup for per-word I/O loops
+ */
+void spi_bitbang_cleanup(const struct spi_device *spi)
+{
+ kfree(spi->controller_state);
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_cleanup);
+
+static int spi_bitbang_bufs(struct spi_device *spi, struct spi_transfer *t)
+{
+ struct spi_bitbang_cs *cs = spi->controller_state;
+ unsigned nsecs = cs->nsecs;
+
+ return cs->txrx_bufs(spi, cs->txrx_word, nsecs, t);
+}
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * SECOND PART ... simple transfer queue runner.
+ *
+ * This costs a task context per controller, running the queue by
+ * performing each transfer in sequence. Smarter hardware can queue
+ * several DMA transfers at once, and process several controller queues
+ * in parallel; this driver doesn't match such hardware very well.
+ *
+ * Drivers can provide word-at-a-time i/o primitives, or provide
+ * transfer-at-a-time ones to leverage dma or fifo hardware.
+ */
+static void bitbang_work(void *_bitbang)
+{
+ struct spi_bitbang *bitbang = _bitbang;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bitbang->lock, flags);
+ bitbang->busy = 1;
+ while (!list_empty(&bitbang->queue)) {
+ struct spi_message *m;
+ struct spi_device *spi;
+ unsigned nsecs;
+ struct spi_transfer *t = NULL;
+ unsigned tmp;
+ unsigned cs_change;
+ int status;
+
+ m = container_of(bitbang->queue.next, struct spi_message,
+ queue);
+ list_del_init(&m->queue);
+ spin_unlock_irqrestore(&bitbang->lock, flags);
+
+ /* FIXME this is made-up ... the correct value is known to
+ * word-at-a-time bitbang code, and presumably chipselect()
+ * should enforce these requirements too?
+ */
+ nsecs = 100;
+
+ spi = m->spi;
+ tmp = 0;
+ cs_change = 1;
+ status = 0;
+
+ list_for_each_entry (t, &m->transfers, transfer_list) {
+ if (bitbang->shutdown) {
+ status = -ESHUTDOWN;
+ break;
+ }
+
+ /* set up default clock polarity, and activate chip;
+ * this implicitly updates clock and spi modes as
+ * previously recorded for this device via setup().
+ * (and also deselects any other chip that might be
+ * selected ...)
+ */
+ if (cs_change) {
+ bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
+ ndelay(nsecs);
+ }
+ cs_change = t->cs_change;
+ if (!t->tx_buf && !t->rx_buf && t->len) {
+ status = -EINVAL;
+ break;
+ }
+
+ /* transfer data. the lower level code handles any
+ * new dma mappings it needs. our caller always gave
+ * us dma-safe buffers.
+ */
+ if (t->len) {
+ /* REVISIT dma API still needs a designated
+ * DMA_ADDR_INVALID; ~0 might be better.
+ */
+ if (!m->is_dma_mapped)
+ t->rx_dma = t->tx_dma = 0;
+ status = bitbang->txrx_bufs(spi, t);
+ }
+ if (status != t->len) {
+ if (status > 0)
+ status = -EMSGSIZE;
+ break;
+ }
+ m->actual_length += status;
+ status = 0;
+
+ /* protocol tweaks before next transfer */
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ if (!cs_change)
+ continue;
+ if (t->transfer_list.next == &m->transfers)
+ break;
+
+ /* sometimes a short mid-message deselect of the chip
+ * may be needed to terminate a mode or command
+ */
+ ndelay(nsecs);
+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+ ndelay(nsecs);
+ }
+
+ m->status = status;
+ m->complete(m->context);
+
+ /* normally deactivate chipselect ... unless no error and
+ * cs_change has hinted that the next message will probably
+ * be for this chip too.
+ */
+ if (!(status == 0 && cs_change)) {
+ ndelay(nsecs);
+ bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
+ ndelay(nsecs);
+ }
+
+ spin_lock_irqsave(&bitbang->lock, flags);
+ }
+ bitbang->busy = 0;
+ spin_unlock_irqrestore(&bitbang->lock, flags);
+}
+
+/**
+ * spi_bitbang_transfer - default submit to transfer queue
+ */
+int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
+{
+ struct spi_bitbang *bitbang;
+ unsigned long flags;
+
+ m->actual_length = 0;
+ m->status = -EINPROGRESS;
+
+ bitbang = spi_master_get_devdata(spi->master);
+ if (bitbang->shutdown)
+ return -ESHUTDOWN;
+
+ spin_lock_irqsave(&bitbang->lock, flags);
+ list_add_tail(&m->queue, &bitbang->queue);
+ queue_work(bitbang->workqueue, &bitbang->work);
+ spin_unlock_irqrestore(&bitbang->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
+
+/*----------------------------------------------------------------------*/
+
+/**
+ * spi_bitbang_start - start up a polled/bitbanging SPI master driver
+ * @bitbang: driver handle
+ *
+ * Caller should have zero-initialized all parts of the structure, and then
+ * provided callbacks for chip selection and I/O loops. If the master has
+ * a transfer method, its final step should call spi_bitbang_transfer; or,
+ * that's the default if the transfer routine is not initialized. It should
+ * also set up the bus number and number of chipselects.
+ *
+ * For i/o loops, provide callbacks either per-word (for bitbanging, or for
+ * hardware that basically exposes a shift register) or per-spi_transfer
+ * (which takes better advantage of hardware like fifos or DMA engines).
+ *
+ * Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and
+ * spi_bitbang_cleanup to handle those spi master methods. Those methods are
+ * the defaults if the bitbang->txrx_bufs routine isn't initialized.
+ *
+ * This routine registers the spi_master, which will process requests in a
+ * dedicated task, keeping IRQs unblocked most of the time. To stop
+ * processing those requests, call spi_bitbang_stop().
+ */
+int spi_bitbang_start(struct spi_bitbang *bitbang)
+{
+ int status;
+
+ if (!bitbang->master || !bitbang->chipselect)
+ return -EINVAL;
+
+ INIT_WORK(&bitbang->work, bitbang_work, bitbang);
+ spin_lock_init(&bitbang->lock);
+ INIT_LIST_HEAD(&bitbang->queue);
+
+ if (!bitbang->master->transfer)
+ bitbang->master->transfer = spi_bitbang_transfer;
+ if (!bitbang->txrx_bufs) {
+ bitbang->use_dma = 0;
+ bitbang->txrx_bufs = spi_bitbang_bufs;
+ if (!bitbang->master->setup) {
+ bitbang->master->setup = spi_bitbang_setup;
+ bitbang->master->cleanup = spi_bitbang_cleanup;
+ }
+ } else if (!bitbang->master->setup)
+ return -EINVAL;
+
+ /* this task is the only thing to touch the SPI bits */
+ bitbang->busy = 0;
+ bitbang->workqueue = create_singlethread_workqueue(
+ bitbang->master->cdev.dev->bus_id);
+ if (bitbang->workqueue == NULL) {
+ status = -EBUSY;
+ goto err1;
+ }
+
+ /* driver may get busy before register() returns, especially
+ * if someone registered boardinfo for devices
+ */
+ status = spi_register_master(bitbang->master);
+ if (status < 0)
+ goto err2;
+
+ return status;
+
+err2:
+ destroy_workqueue(bitbang->workqueue);
+err1:
+ return status;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_start);
+
+/**
+ * spi_bitbang_stop - stops the task providing spi communication
+ */
+int spi_bitbang_stop(struct spi_bitbang *bitbang)
+{
+ unsigned limit = 500;
+
+ spin_lock_irq(&bitbang->lock);
+ bitbang->shutdown = 0;
+ while (!list_empty(&bitbang->queue) && limit--) {
+ spin_unlock_irq(&bitbang->lock);
+
+ dev_dbg(bitbang->master->cdev.dev, "wait for queue\n");
+ msleep(10);
+
+ spin_lock_irq(&bitbang->lock);
+ }
+ spin_unlock_irq(&bitbang->lock);
+ if (!list_empty(&bitbang->queue)) {
+ dev_err(bitbang->master->cdev.dev, "queue didn't empty\n");
+ return -EBUSY;
+ }
+
+ destroy_workqueue(bitbang->workqueue);
+
+ spi_unregister_master(bitbang->master);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_bitbang_stop);
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/spi/spi_butterfly.c b/drivers/spi/spi_butterfly.c
new file mode 100644
index 00000000000..79a3c59615a
--- /dev/null
+++ b/drivers/spi/spi_butterfly.c
@@ -0,0 +1,423 @@
+/*
+ * spi_butterfly.c - parport-to-butterfly adapter
+ *
+ * Copyright (C) 2005 David Brownell
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/parport.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/flash.h>
+
+#include <linux/mtd/partitions.h>
+
+
+/*
+ * This uses SPI to talk with an "AVR Butterfly", which is a $US20 card
+ * with a battery powered AVR microcontroller and lots of goodies. You
+ * can use GCC to develop firmware for this.
+ *
+ * See Documentation/spi/butterfly for information about how to build
+ * and use this custom parallel port cable.
+ */
+
+#undef HAVE_USI /* nyet */
+
+
+/* DATA output bits (pins 2..9 == D0..D7) */
+#define butterfly_nreset (1 << 1) /* pin 3 */
+
+#define spi_sck_bit (1 << 0) /* pin 2 */
+#define spi_mosi_bit (1 << 7) /* pin 9 */
+
+#define usi_sck_bit (1 << 3) /* pin 5 */
+#define usi_mosi_bit (1 << 4) /* pin 6 */
+
+#define vcc_bits ((1 << 6) | (1 << 5)) /* pins 7, 8 */
+
+/* STATUS input bits */
+#define spi_miso_bit PARPORT_STATUS_BUSY /* pin 11 */
+
+#define usi_miso_bit PARPORT_STATUS_PAPEROUT /* pin 12 */
+
+/* CONTROL output bits */
+#define spi_cs_bit PARPORT_CONTROL_SELECT /* pin 17 */
+/* USI uses no chipselect */
+
+
+
+static inline struct butterfly *spidev_to_pp(struct spi_device *spi)
+{
+ return spi->controller_data;
+}
+
+static inline int is_usidev(struct spi_device *spi)
+{
+#ifdef HAVE_USI
+ return spi->chip_select != 1;
+#else
+ return 0;
+#endif
+}
+
+
+struct butterfly {
+ /* REVISIT ... for now, this must be first */
+ struct spi_bitbang bitbang;
+
+ struct parport *port;
+ struct pardevice *pd;
+
+ u8 lastbyte;
+
+ struct spi_device *dataflash;
+ struct spi_device *butterfly;
+ struct spi_board_info info[2];
+
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * these routines may be slower than necessary because they're hiding
+ * the fact that there are two different SPI busses on this cable: one
+ * to the DataFlash chip (or AVR SPI controller), the other to the
+ * AVR USI controller.
+ */
+
+static inline void
+setsck(struct spi_device *spi, int is_on)
+{
+ struct butterfly *pp = spidev_to_pp(spi);
+ u8 bit, byte = pp->lastbyte;
+
+ if (is_usidev(spi))
+ bit = usi_sck_bit;
+ else
+ bit = spi_sck_bit;
+
+ if (is_on)
+ byte |= bit;
+ else
+ byte &= ~bit;
+ parport_write_data(pp->port, byte);
+ pp->lastbyte = byte;
+}
+
+static inline void
+setmosi(struct spi_device *spi, int is_on)
+{
+ struct butterfly *pp = spidev_to_pp(spi);
+ u8 bit, byte = pp->lastbyte;
+
+ if (is_usidev(spi))
+ bit = usi_mosi_bit;
+ else
+ bit = spi_mosi_bit;
+
+ if (is_on)
+ byte |= bit;
+ else
+ byte &= ~bit;
+ parport_write_data(pp->port, byte);
+ pp->lastbyte = byte;
+}
+
+static inline int getmiso(struct spi_device *spi)
+{
+ struct butterfly *pp = spidev_to_pp(spi);
+ int value;
+ u8 bit;
+
+ if (is_usidev(spi))
+ bit = usi_miso_bit;
+ else
+ bit = spi_miso_bit;
+
+ /* only STATUS_BUSY is NOT negated */
+ value = !(parport_read_status(pp->port) & bit);
+ return (bit == PARPORT_STATUS_BUSY) ? value : !value;
+}
+
+static void butterfly_chipselect(struct spi_device *spi, int value)
+{
+ struct butterfly *pp = spidev_to_pp(spi);
+
+ /* set default clock polarity */
+ if (value)
+ setsck(spi, spi->mode & SPI_CPOL);
+
+ /* no chipselect on this USI link config */
+ if (is_usidev(spi))
+ return;
+
+ /* here, value == "activate or not" */
+
+ /* most PARPORT_CONTROL_* bits are negated */
+ if (spi_cs_bit == PARPORT_CONTROL_INIT)
+ value = !value;
+
+ /* here, value == "bit value to write in control register" */
+
+ parport_frob_control(pp->port, spi_cs_bit, value ? spi_cs_bit : 0);
+}
+
+
+/* we only needed to implement one mode here, and choose SPI_MODE_0 */
+
+#define spidelay(X) do{}while(0)
+//#define spidelay ndelay
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32
+butterfly_txrx_word_mode0(struct spi_device *spi,
+ unsigned nsecs,
+ u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+/*----------------------------------------------------------------------*/
+
+/* override default partitioning with cmdlinepart */
+static struct mtd_partition partitions[] = { {
+ /* JFFS2 wants partitions of 4*N blocks for this device ... */
+
+ /* sector 0 = 8 pages * 264 bytes/page (1 block)
+ * sector 1 = 248 pages * 264 bytes/page
+ */
+ .name = "bookkeeping", // 66 KB
+ .offset = 0,
+ .size = (8 + 248) * 264,
+// .mask_flags = MTD_WRITEABLE,
+}, {
+ /* sector 2 = 256 pages * 264 bytes/page
+ * sectors 3-5 = 512 pages * 264 bytes/page
+ */
+ .name = "filesystem", // 462 KB
+ .offset = MTDPART_OFS_APPEND,
+ .size = MTDPART_SIZ_FULL,
+} };
+
+static struct flash_platform_data flash = {
+ .name = "butterflash",
+ .parts = partitions,
+ .nr_parts = ARRAY_SIZE(partitions),
+};
+
+
+/* REVISIT remove this ugly global and its "only one" limitation */
+static struct butterfly *butterfly;
+
+static void butterfly_attach(struct parport *p)
+{
+ struct pardevice *pd;
+ int status;
+ struct butterfly *pp;
+ struct spi_master *master;
+ struct platform_device *pdev;
+
+ if (butterfly)
+ return;
+
+ /* REVISIT: this just _assumes_ a butterfly is there ... no probe,
+ * and no way to be selective about what it binds to.
+ */
+
+ /* FIXME where should master->cdev.dev come from?
+ * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc
+ * setting up a platform device like this is an ugly kluge...
+ */
+ pdev = platform_device_register_simple("butterfly", -1, NULL, 0);
+
+ master = spi_alloc_master(&pdev->dev, sizeof *pp);
+ if (!master) {
+ status = -ENOMEM;
+ goto done;
+ }
+ pp = spi_master_get_devdata(master);
+
+ /*
+ * SPI and bitbang hookup
+ *
+ * use default setup(), cleanup(), and transfer() methods; and
+ * only bother implementing mode 0. Start it later.
+ */
+ master->bus_num = 42;
+ master->num_chipselect = 2;
+
+ pp->bitbang.master = spi_master_get(master);
+ pp->bitbang.chipselect = butterfly_chipselect;
+ pp->bitbang.txrx_word[SPI_MODE_0] = butterfly_txrx_word_mode0;
+
+ /*
+ * parport hookup
+ */
+ pp->port = p;
+ pd = parport_register_device(p, "spi_butterfly",
+ NULL, NULL, NULL,
+ 0 /* FLAGS */, pp);
+ if (!pd) {
+ status = -ENOMEM;
+ goto clean0;
+ }
+ pp->pd = pd;
+
+ status = parport_claim(pd);
+ if (status < 0)
+ goto clean1;
+
+ /*
+ * Butterfly reset, powerup, run firmware
+ */
+ pr_debug("%s: powerup/reset Butterfly\n", p->name);
+
+ /* nCS for dataflash (this bit is inverted on output) */
+ parport_frob_control(pp->port, spi_cs_bit, 0);
+
+ /* stabilize power with chip in reset (nRESET), and
+ * both spi_sck_bit and usi_sck_bit clear (CPOL=0)
+ */
+ pp->lastbyte |= vcc_bits;
+ parport_write_data(pp->port, pp->lastbyte);
+ msleep(5);
+
+ /* take it out of reset; assume long reset delay */
+ pp->lastbyte |= butterfly_nreset;
+ parport_write_data(pp->port, pp->lastbyte);
+ msleep(100);
+
+
+ /*
+ * Start SPI ... for now, hide that we're two physical busses.
+ */
+ status = spi_bitbang_start(&pp->bitbang);
+ if (status < 0)
+ goto clean2;
+
+ /* Bus 1 lets us talk to at45db041b (firmware disables AVR)
+ * or AVR (firmware resets at45, acts as spi slave)
+ */
+ pp->info[0].max_speed_hz = 15 * 1000 * 1000;
+ strcpy(pp->info[0].modalias, "mtd_dataflash");
+ pp->info[0].platform_data = &flash;
+ pp->info[0].chip_select = 1;
+ pp->info[0].controller_data = pp;
+ pp->dataflash = spi_new_device(pp->bitbang.master, &pp->info[0]);
+ if (pp->dataflash)
+ pr_debug("%s: dataflash at %s\n", p->name,
+ pp->dataflash->dev.bus_id);
+
+#ifdef HAVE_USI
+ /* even more custom AVR firmware */
+ pp->info[1].max_speed_hz = 10 /* ?? */ * 1000 * 1000;
+ strcpy(pp->info[1].modalias, "butterfly");
+ // pp->info[1].platform_data = ... TBD ... ;
+ pp->info[1].chip_select = 2,
+ pp->info[1].controller_data = pp;
+ pp->butterfly = spi_new_device(pp->bitbang.master, &pp->info[1]);
+ if (pp->butterfly)
+ pr_debug("%s: butterfly at %s\n", p->name,
+ pp->butterfly->dev.bus_id);
+
+ /* FIXME setup ACK for the IRQ line ... */
+#endif
+
+ // dev_info(_what?_, ...)
+ pr_info("%s: AVR Butterfly\n", p->name);
+ butterfly = pp;
+ return;
+
+clean2:
+ /* turn off VCC */
+ parport_write_data(pp->port, 0);
+
+ parport_release(pp->pd);
+clean1:
+ parport_unregister_device(pd);
+clean0:
+ (void) spi_master_put(pp->bitbang.master);
+done:
+ platform_device_unregister(pdev);
+ pr_debug("%s: butterfly probe, fail %d\n", p->name, status);
+}
+
+static void butterfly_detach(struct parport *p)
+{
+ struct butterfly *pp;
+ struct platform_device *pdev;
+ int status;
+
+ /* FIXME this global is ugly ... but, how to quickly get from
+ * the parport to the "struct butterfly" associated with it?
+ * "old school" driver-internal device lists?
+ */
+ if (!butterfly || butterfly->port != p)
+ return;
+ pp = butterfly;
+ butterfly = NULL;
+
+#ifdef HAVE_USI
+ spi_unregister_device(pp->butterfly);
+ pp->butterfly = NULL;
+#endif
+ spi_unregister_device(pp->dataflash);
+ pp->dataflash = NULL;
+
+ status = spi_bitbang_stop(&pp->bitbang);
+
+ /* turn off VCC */
+ parport_write_data(pp->port, 0);
+ msleep(10);
+
+ parport_release(pp->pd);
+ parport_unregister_device(pp->pd);
+
+ pdev = to_platform_device(pp->bitbang.master->cdev.dev);
+
+ (void) spi_master_put(pp->bitbang.master);
+
+ platform_device_unregister(pdev);
+}
+
+static struct parport_driver butterfly_driver = {
+ .name = "spi_butterfly",
+ .attach = butterfly_attach,
+ .detach = butterfly_detach,
+};
+
+
+static int __init butterfly_init(void)
+{
+ return parport_register_driver(&butterfly_driver);
+}
+device_initcall(butterfly_init);
+
+static void __exit butterfly_exit(void)
+{
+ parport_unregister_driver(&butterfly_driver);
+}
+module_exit(butterfly_exit);
+
+MODULE_LICENSE("GPL");