[PATCH] spi: add spi_driver to SPI framework

This is a refresh of the "Simple SPI Framework" found in 2.6.15-rc3-mm1
which makes the following changes:

  * There's now a "struct spi_driver".  This increase the footprint
    of the core a bit, since it now includes code to do what the driver
    core was previously handling directly.  Documentation and comments
    were updated to match.

  * spi_alloc_master() now does class_device_initialize(), so it can
    at least be refcounted before spi_register_master().  To match,
    spi_register_master() switched over to class_device_add().

  * States explicitly that after transfer errors, spi_devices will be
    deselected.  We want fault recovery procedures to work the same
    for all controller drivers.

  * Minor tweaks:  controller_data no longer points to readonly data;
    prevent some potential cast-from-null bugs with container_of calls;
    clarifies some existing kerneldoc,

And a few small cleanups.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 7cd356b..2ecb86c 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -26,13 +26,9 @@
 #include <linux/spi/spi.h>
 
 
-/* SPI bustype and spi_master class are registered during early boot,
- * usually before board init code provides the SPI device tables, and
- * are available later when driver init code needs them.
- *
- * Drivers for SPI devices started out like those for platform bus
- * devices.  But both have changed in 2.6.15; maybe this should get
- * an "spi_driver" structure at some point (not currently needed)
+/* 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)
 {
@@ -83,10 +79,7 @@
 
 #ifdef	CONFIG_PM
 
-/* Suspend/resume in "struct device_driver" don't really need that
- * strange third parameter, so we just make it a constant and expect
- * SPI drivers to ignore it just like most platform drivers do.
- *
+/*
  * 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
@@ -94,13 +87,14 @@
  */
 static int spi_suspend(struct device *dev, pm_message_t message)
 {
-	int	value;
+	int			value;
+	struct spi_driver	*drv = to_spi_driver(dev->driver);
 
-	if (!dev->driver || !dev->driver->suspend)
+	if (!drv || !drv->suspend)
 		return 0;
 
 	/* suspend will stop irqs and dma; no more i/o */
-	value = dev->driver->suspend(dev, message);
+	value = drv->suspend(to_spi_device(dev), message);
 	if (value == 0)
 		dev->power.power_state = message;
 	return value;
@@ -108,13 +102,14 @@
 
 static int spi_resume(struct device *dev)
 {
-	int	value;
+	int			value;
+	struct spi_driver	*drv = to_spi_driver(dev->driver);
 
-	if (!dev->driver || !dev->driver->resume)
+	if (!drv || !drv->resume)
 		return 0;
 
 	/* resume may restart the i/o queue */
-	value = dev->driver->resume(dev);
+	value = drv->resume(to_spi_device(dev));
 	if (value == 0)
 		dev->power.power_state = PMSG_ON;
 	return value;
@@ -135,6 +130,41 @@
 };
 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
@@ -208,13 +238,15 @@
 	if (status < 0) {
 		dev_dbg(dev, "can't %s %s, status %d\n",
 				"add", proxy->dev.bus_id, status);
-fail:
-		class_device_put(&master->cdev);
-		kfree(proxy);
-		return NULL;
+		goto fail;
 	}
 	dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
 	return proxy;
+
+fail:
+	class_device_put(&master->cdev);
+	kfree(proxy);
+	return NULL;
 }
 EXPORT_SYMBOL_GPL(spi_new_device);
 
@@ -237,11 +269,11 @@
 {
 	struct boardinfo	*bi;
 
-	bi = kmalloc (sizeof (*bi) + n * sizeof (*info), GFP_KERNEL);
+	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));
+	memcpy(bi->board_info, info, n * sizeof *info);
 
 	down(&board_lock);
 	list_add_tail(&bi->list, &board_list);
@@ -330,6 +362,7 @@
 	if (!master)
 		return NULL;
 
+	class_device_initialize(&master->cdev);
 	master->cdev.class = &spi_master_class;
 	master->cdev.dev = get_device(dev);
 	class_set_devdata(&master->cdev, &master[1]);
@@ -366,7 +399,7 @@
 	/* 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 = 0;
+		dynamic = 1;
 	}
 
 	/* register the device, then userspace will see it.
@@ -374,11 +407,9 @@
 	 */
 	snprintf(master->cdev.class_id, sizeof master->cdev.class_id,
 		"spi%u", master->bus_num);
-	status = class_device_register(&master->cdev);
-	if (status < 0) {
-		class_device_put(&master->cdev);
+	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)" : "");
 
@@ -491,6 +522,7 @@
  * 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,
  * large transfers should use use spi_{async,sync}() calls with
@@ -553,16 +585,38 @@
 
 static int __init spi_init(void)
 {
-	buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
-	if (!buf)
-		return -ENOMEM;
+	int	status;
 
-	bus_register(&spi_bus_type);
-	class_register(&spi_master_class);
+	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);