Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 106876
b: refs/heads/master
c: dc87c98
h: refs/heads/master
v: v3
  • Loading branch information
Grant Likely committed Jul 26, 2008
1 parent ab8e27d commit 501a869
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 45 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 3f07af494dfa6de43137dae430431c9fbf929c0c
refs/heads/master: dc87c98e8f635a718f1abb2c3e15fc77c0001651
139 changes: 95 additions & 44 deletions trunk/drivers/spi/spi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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);

Expand Down
12 changes: 12 additions & 0 deletions trunk/include/linux/spi/spi.h
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,19 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
* use spi_new_device() to describe each device. You can also call
* spi_unregister_device() to start making that device vanish, but
* normally that would be handled by spi_unregister_master().
*
* You can also use spi_alloc_device() and spi_add_device() to use a two
* stage registration sequence for each spi_device. This gives the caller
* some more control over the spi_device structure before it is registered,
* but requires that caller to initialize fields that would otherwise
* be defined using the board info.
*/
extern struct spi_device *
spi_alloc_device(struct spi_master *master);

extern int
spi_add_device(struct spi_device *spi);

extern struct spi_device *
spi_new_device(struct spi_master *, struct spi_board_info *);

Expand Down

0 comments on commit 501a869

Please sign in to comment.