aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi/spi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-28 09:05:35 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-28 09:05:35 -0700
commitd9089c296bdd82e6c1b7f82d04c11b5decde75e7 (patch)
tree6c2a3b8bc1b6f8b5930f6a20b099511dd19aa4ba /drivers/spi/spi.c
parentbda426f5310ffddcd463fe20f352609e84989514 (diff)
parent00df438e89a9003895948170e1abf64dd4665872 (diff)
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (25 commits) powerpc: Disable 64K hugetlb support when doing 64K SPU mappings powerpc/powermac: Fixup default serial port device for pmac_zilog powerpc/powermac: Use sane default baudrate for SCC debugging powerpc/mm: Implement _PAGE_SPECIAL & pte_special() for 64-bit powerpc: Show processor cache information in sysfs powerpc: Make core id information available to userspace powerpc: Make core sibling information available to userspace powerpc/vio: More fallout from dma_mapping_error API change ibmveth: Fix multiple errors with dma_mapping_error conversion powerpc/pseries: Fix CMO sysdev attribute API change fallout powerpc: Enable tracehook for the architecture powerpc: Add TIF_NOTIFY_RESUME support for tracehook powerpc: Add asm/syscall.h with the tracehook entry points powerpc: Make syscall tracing use tracehook.h helpers powerpc: Call tracehook_signal_handler() when setting up signal frames powerpc: Update cpu_sibling_maps dynamically powerpc: register_cpu_online should be __cpuinit powerpc: kill useless SMT code in prom_hold_cpus powerpc: Fix 8xx build failure powerpc: Fix vio build warnings ...
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r--drivers/spi/spi.c139
1 files changed, 95 insertions, 44 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index ecca4a6a6f9..964124b60db 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -178,6 +178,96 @@ struct boardinfo {
static LIST_HEAD(board_list);
static DEFINE_MUTEX(board_lock);
+/**
+ * spi_alloc_device - Allocate a new SPI device
+ * @master: Controller to which device is connected
+ * Context: can sleep
+ *
+ * Allows a driver to allocate and initialize a spi_device without
+ * registering it immediately. This allows a driver to directly
+ * fill the spi_device with device parameters before calling
+ * spi_add_device() on it.
+ *
+ * Caller is responsible to call spi_add_device() on the returned
+ * spi_device structure to add it to the SPI master. If the caller
+ * needs to discard the spi_device without adding it, then it should
+ * call spi_dev_put() on it.
+ *
+ * Returns a pointer to the new device, or NULL.
+ */
+struct spi_device *spi_alloc_device(struct spi_master *master)
+{
+ struct spi_device *spi;
+ struct device *dev = master->dev.parent;
+
+ if (!spi_master_get(master))
+ return NULL;
+
+ spi = kzalloc(sizeof *spi, GFP_KERNEL);
+ if (!spi) {
+ dev_err(dev, "cannot alloc spi_device\n");
+ spi_master_put(master);
+ return NULL;
+ }
+
+ spi->master = master;
+ spi->dev.parent = dev;
+ spi->dev.bus = &spi_bus_type;
+ spi->dev.release = spidev_release;
+ device_initialize(&spi->dev);
+ return spi;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_device);
+
+/**
+ * spi_add_device - Add spi_device allocated with spi_alloc_device
+ * @spi: spi_device to register
+ *
+ * Companion function to spi_alloc_device. Devices allocated with
+ * spi_alloc_device can be added onto the spi bus with this function.
+ *
+ * Returns 0 on success; non-zero on failure
+ */
+int spi_add_device(struct spi_device *spi)
+{
+ struct device *dev = spi->master->dev.parent;
+ int status;
+
+ /* Chipselects are numbered 0..max; validate. */
+ if (spi->chip_select >= spi->master->num_chipselect) {
+ dev_err(dev, "cs%d >= max %d\n",
+ spi->chip_select,
+ spi->master->num_chipselect);
+ return -EINVAL;
+ }
+
+ /* Set the bus ID string */
+ snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id,
+ "%s.%u", spi->master->dev.bus_id,
+ spi->chip_select);
+
+ /* drivers may modify this initial i/o setup */
+ status = spi->master->setup(spi);
+ if (status < 0) {
+ dev_err(dev, "can't %s %s, status %d\n",
+ "setup", spi->dev.bus_id, status);
+ return status;
+ }
+
+ /* driver core catches callers that misbehave by defining
+ * devices that already exist.
+ */
+ status = device_add(&spi->dev);
+ if (status < 0) {
+ dev_err(dev, "can't %s %s, status %d\n",
+ "add", spi->dev.bus_id, status);
+ return status;
+ }
+
+ dev_dbg(dev, "registered child %s\n", spi->dev.bus_id);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_add_device);
/**
* spi_new_device - instantiate one new SPI device
@@ -197,7 +287,6 @@ struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
{
struct spi_device *proxy;
- struct device *dev = master->dev.parent;
int status;
/* NOTE: caller did any chip->bus_num checks necessary.
@@ -207,66 +296,28 @@ struct spi_device *spi_new_device(struct spi_master *master,
* suggests syslogged diagnostics are best here (ugh).
*/
- /* Chipselects are numbered 0..max; validate. */
- if (chip->chip_select >= master->num_chipselect) {
- dev_err(dev, "cs%d > max %d\n",
- chip->chip_select,
- master->num_chipselect);
- return NULL;
- }
-
- if (!spi_master_get(master))
+ proxy = spi_alloc_device(master);
+ if (!proxy)
return NULL;
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
- 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->mode = chip->mode;
proxy->irq = chip->irq;
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
-
- snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
- "%s.%u", master->dev.bus_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 initial i/o setup */
- status = master->setup(proxy);
+ status = spi_add_device(proxy);
if (status < 0) {
- dev_err(dev, "can't %s %s, status %d\n",
- "setup", proxy->dev.bus_id, status);
- goto fail;
+ spi_dev_put(proxy);
+ return NULL;
}
- /* driver core catches callers that misbehave by defining
- * devices that already exist.
- */
- status = device_register(&proxy->dev);
- if (status < 0) {
- dev_err(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);