#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)
{
if (spi->master->cleanup)
spi->master->cleanup(spi);
- class_device_put(&spi->master->cdev);
+ spi_master_put(spi->master);
kfree(dev);
}
#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
*/
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->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;
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->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;
};
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
/* NOTE: caller did any chip->bus_num checks necessary */
- if (!class_device_get(&master->cdev))
+ if (!spi_master_get(master))
return NULL;
proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
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:
+ spi_master_put(master);
+ kfree(proxy);
+ return NULL;
}
EXPORT_SYMBOL_GPL(spi_new_device);
{
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);
struct spi_master *master;
master = container_of(cdev, struct spi_master, cdev);
- put_device(master->cdev.dev);
- master->cdev.dev = NULL;
kfree(master);
}
/**
* spi_alloc_master - allocate SPI master controller
* @dev: the controller, possibly using the platform_bus
- * @size: how much driver-private data to preallocate; a pointer to this
- * memory in the class_data field of the returned class_device
+ * @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
* 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(), or else (on error)
- * calling class_device_put() to prevent a memory leak.
+ * 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);
- class_set_devdata(&master->cdev, &master[1]);
+ spi_master_set_devdata(master, &master[1]);
return master;
}
*
* 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)
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 = 0;
+ dynamic = 1;
}
/* register the device, then userspace will see it.
*/
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)" : "");
static int __unregister(struct device *dev, void *unused)
{
/* note: before about 2.6.14-rc1 this would corrupt memory: */
- device_unregister(dev);
+ spi_unregister_device(to_spi_device(dev));
return 0;
}
*/
void spi_unregister_master(struct spi_master *master)
{
- class_device_unregister(&master->cdev);
(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);
/*-------------------------------------------------------------------------*/
+static void spi_complete(void *arg)
+{
+ complete(arg);
+}
+
/**
* spi_sync - blocking/synchronous SPI data transfers
* @spi: device with which data will be exchanged
* 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
DECLARE_COMPLETION(done);
int status;
- message->complete = (void (*)(void *)) complete;
+ message->complete = spi_complete;
message->context = &done;
status = spi_async(spi, message);
if (status == 0)
* 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
- * dma-safe buffers.
+ * 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,
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);
} else
local_buf = buf;
- memset(x, 0, sizeof x);
-
memcpy(local_buf, txbuf, n_tx);
x[0].tx_buf = local_buf;
- x[0].len = n_tx;
-
x[1].rx_buf = local_buf + n_tx;
- x[1].len = n_rx;
/* do the i/o */
- message.transfers = x;
- message.n_transfer = ARRAY_SIZE(x);
status = spi_sync(spi, &message);
if (status == 0) {
memcpy(rxbuf, x[1].rx_buf, n_rx);
static int __init spi_init(void)
{
+ int status;
+
buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
- if (!buf)
- return -ENOMEM;
+ if (!buf) {
+ status = -ENOMEM;
+ goto err0;
+ }
+
+ status = bus_register(&spi_bus_type);
+ if (status < 0)
+ goto err1;
- bus_register(&spi_bus_type);
- class_register(&spi_master_class);
+ 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);