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