From: Ken Mills <ken.k.mills-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
To: David Brownell
<dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>,
spi mailing list
<spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>
Cc: Ken Mills <ken.k.mills-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Subject: [PATCH] This adds support for SPI slave controller drivers
Date: Fri, 12 Jun 2009 10:44:13 -0700 [thread overview]
Message-ID: <1244828653.3513.16.camel@ubuntu-vmware> (raw)
Second try sending SPI core patch.
Signed-off-by: Ken Mills <ken.k.mills-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
drivers/spi/spi.c | 368 ++++++++++++++++++++++++++++++++++++++++++-----
include/linux/spi/spi.h | 100 ++++++++++++-
2 files changed, 427 insertions(+), 41 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 8eba98c..504f0ae 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -26,19 +26,34 @@
#include <linux/spi/spi.h>
-/* 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".
- */
+/* SPI bustype, spi_master and spi_slave 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".
+*/
+
+/* SPI Slave Support is added for new spi slave devices: It uses common APIs,
+* apart from few new APIs and a spi_slave structure.
+*/
+
static void spidev_release(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
- /* spi masters may cleanup for released devices */
- if (spi->master->cleanup)
- spi->master->cleanup(spi);
+ if (spi->master) {
+ /* spi masters may cleanup for released devices */
+ if (spi->master->cleanup)
+ spi->master->cleanup(spi);
+
+ spi_master_put(spi->master);
+ } else {
+ /* spi slave controller */
+ if (spi->slave->cleanup)
+ spi->slave->cleanup(spi);
+
+ spi_slave_put(spi->slave);
+ }
- spi_master_put(spi->master);
kfree(dev);
}
@@ -46,7 +61,6 @@ static ssize_t
modalias_show(struct device *dev, struct device_attribute *a, char *buf)
{
const struct spi_device *spi = to_spi_device(dev);
-
return sprintf(buf, "%s\n", spi->modalias);
}
@@ -62,14 +76,12 @@ static struct device_attribute spi_dev_attrs[] = {
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
-
return strcmp(spi->modalias, drv->name) == 0;
}
static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
-
add_uevent_var(env, "MODALIAS=%s", spi->modalias);
return 0;
}
@@ -153,10 +165,13 @@ 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);
@@ -197,28 +212,70 @@ static DEFINE_MUTEX(board_lock);
*/
struct spi_device *spi_alloc_device(struct spi_master *master)
{
- struct spi_device *spi;
+ struct spi_device *spi_m_dev;
struct device *dev = master->dev.parent;
if (!spi_master_get(master))
return NULL;
- spi = kzalloc(sizeof *spi, GFP_KERNEL);
- if (!spi) {
+ spi_m_dev = kzalloc(sizeof *spi_m_dev, GFP_KERNEL);
+ if (!spi_m_dev) {
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;
+ spi_m_dev->master = master;
+ spi_m_dev->slave = NULL;
+ spi_m_dev->dev.parent = dev;
+ spi_m_dev->dev.bus = &spi_bus_type;
+ spi_m_dev->dev.release = spidev_release;
+ device_initialize(&spi_m_dev->dev);
+ return spi_m_dev;
}
EXPORT_SYMBOL_GPL(spi_alloc_device);
+/*
+* spi_alloc_slave_device - Allocate a new SPI device
+* @slave: 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_slave_device() on it.
+*
+* Caller is responsible to call spi_add_slave_device() on the returned
+* spi_device structure to add it to the SPI slave. If the caller
+* needs to discard the spi_device without adding it, then it should
+* call spi_dev_slave_put() on it.
+* Returns a pointer to the new device, or NULL.
+*/
+struct spi_device *spi_alloc_slave_device(struct spi_slave *slave)
+{
+ struct spi_device *spi_s;
+ struct device *dev = slave->dev.parent;
+
+ if (!spi_slave_get(slave))
+ return NULL;
+
+ spi_s = kzalloc(sizeof *spi_s, GFP_KERNEL);
+ if (!spi_s) {
+ dev_err(dev, "cannot alloc spi_slave_device\n");
+ spi_slave_put(slave);
+ return NULL;
+ }
+
+ spi_s->slave = slave;
+ spi_s->master = NULL;
+ spi_s->dev.parent = dev;
+ spi_s->dev.bus = &spi_bus_type;
+ spi_s->dev.release = spidev_release;
+ device_initialize(&spi_s->dev);
+ return spi_s;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_slave_device);
+
/**
* spi_add_device - Add spi_device allocated with spi_alloc_device
* @spi: spi_device to register
@@ -231,21 +288,29 @@ EXPORT_SYMBOL_GPL(spi_alloc_device);
int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
- 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;
- }
-
+ struct device *dev;
+
+ if (spi->master) {
+ /* Master Controller */
+ dev = spi->master->dev.parent;
+ /* 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 */
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
spi->chip_select);
-
+ } else {
+ /* Slave Controller */
+ dev = spi->slave->dev.parent;
+ /* Set the bus ID string */
+ dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->slave->dev),
+ spi->chip_select);
+ }
/* We need to make sure there's no other device with this
* chipselect **BEFORE** we call setup(), else we'll trash
@@ -265,7 +330,11 @@ int spi_add_device(struct spi_device *spi)
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
- status = spi->master->setup(spi);
+ if (spi->master)
+ status = spi->master->setup(spi);
+ else
+ status = spi->slave->setup(spi); /* Slave Controller */
+
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", dev_name(&spi->dev), status);
@@ -286,6 +355,7 @@ done:
}
EXPORT_SYMBOL_GPL(spi_add_device);
+
/**
* spi_new_device - instantiate one new SPI device
* @master: Controller to which device is connected
@@ -317,6 +387,8 @@ struct spi_device *spi_new_device(struct spi_master *master,
if (!proxy)
return NULL;
+
+
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
proxy->chip_select = chip->chip_select;
@@ -339,6 +411,54 @@ struct spi_device *spi_new_device(struct spi_master *master,
EXPORT_SYMBOL_GPL(spi_new_device);
/**
+* spi_slave_new_device - instantiate one new SPI device
+* @slave: Controller to which device is connected
+* @chip: Describes the SPI device
+* Context: can sleep
+*
+* On typical mainboards, this is purely internal; and it's not needed
+* after board init creates the hard-wired devices. Some development
+* platforms may not be able to use spi_register_board_info though, and
+* this is exported so that for example a USB or parport based adapter
+* driver could add devices (which it would learn about out-of-band).
+*
+* Returns the new device, or NULL.
+*/
+struct spi_device *spi_slave_new_device(struct spi_slave *slave,
+ struct spi_board_info *chip)
+{
+ struct spi_device *proxy_slave;
+ int status;
+
+ proxy_slave = spi_alloc_slave_device(slave);
+
+ if (!proxy_slave)
+ return NULL;
+
+ WARN_ON(strlen(chip->modalias) >= sizeof(proxy_slave->modalias));
+
+ proxy_slave->chip_select = chip->chip_select;
+ proxy_slave->max_speed_hz = chip->max_speed_hz;
+ proxy_slave->mode = chip->mode;
+ proxy_slave->irq = chip->irq;
+ strlcpy(proxy_slave->modalias, chip->modalias,
+ sizeof(proxy_slave->modalias));
+ proxy_slave->dev.platform_data = (void *) chip->platform_data;
+ proxy_slave->controller_data = chip->controller_data;
+ proxy_slave->controller_state = NULL;
+
+ status = spi_add_device(proxy_slave);
+ if (status < 0) {
+ spi_dev_put(proxy_slave);
+ return NULL;
+ }
+
+ return proxy_slave;
+}
+EXPORT_SYMBOL_GPL(spi_slave_new_device);
+
+
+/**
* spi_register_board_info - register SPI devices for a given board
* @info: array of chip descriptors
* @n: how many descriptors are provided
@@ -365,6 +485,7 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
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);
@@ -374,6 +495,7 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
return 0;
}
+
/* FIXME someone should add support for a __setup("spi", ...) that
* creates board info from kernel command lines
*/
@@ -399,6 +521,28 @@ static void scan_boardinfo(struct spi_master *master)
mutex_unlock(&board_lock);
}
+static void spi_slave_scan_boardinfo(struct spi_slave *slave)
+{
+ struct boardinfo *bi;
+
+ mutex_lock(&board_lock);
+ list_for_each_entry(bi, &board_list, list) {
+ struct spi_board_info *chip = bi->board_info;
+ unsigned n;
+
+ for (n = bi->n_board_info; n > 0; n--, chip++) {
+ if (chip->bus_num != slave->bus_num)
+ continue;
+ /* NOTE: this relies on spi_new_device to
+ * issue diagnostics when given bogus inputs
+ */
+ (void) spi_slave_new_device(slave, chip);
+
+ }
+ }
+ mutex_unlock(&board_lock);
+}
+
/*-------------------------------------------------------------------------*/
static void spi_master_release(struct device *dev)
@@ -415,6 +559,19 @@ static struct class spi_master_class = {
.dev_release = spi_master_release,
};
+static void spi_slave_release(struct device *dev)
+{
+ struct spi_slave *slave;
+
+ slave = container_of(dev, struct spi_slave, dev);
+ kfree(slave);
+}
+
+static struct class spi_slave_class = {
+ .name = "spi_slave",
+ .owner = THIS_MODULE,
+ .dev_release = spi_slave_release,
+};
/**
* spi_alloc_master - allocate SPI master controller
@@ -456,6 +613,47 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
EXPORT_SYMBOL_GPL(spi_alloc_master);
/**
+* spi_alloc_slave - allocate SPI slave controller
+* @dev: the controller, possibly using the platform_bus
+* @size: how much zeroed driver-private data to allocate; the pointer to this
+* memory is in the driver_data field of the returned device,
+* accessible with spi_slave_get_devdata().
+* Context: can sleep
+*
+* This call is used only by SPI master controller drivers, which are the
+* only ones directly touching chip registers. It's how they allocate
+* an spi_master structure, prior to calling spi_register_slave().
+*
+* This must be called from context that can sleep. It returns the SPI
+* master structure on success, else NULL.
+*
+* The caller is responsible for assigning the bus number and initializing
+* the master's methods before calling spi_register_slave(); and (after errors
+* adding the device) calling spi_slave_put() to prevent a memory leak.
+*/
+struct spi_slave *spi_alloc_slave(struct device *dev, unsigned size)
+{
+ struct spi_slave *slave;
+
+ if (!dev)
+ return NULL;
+
+ slave = kzalloc(size + sizeof *slave, GFP_KERNEL);
+ if (!slave)
+ return NULL;
+
+ device_initialize(&slave->dev);
+ slave->dev.class = &spi_slave_class;
+ slave->dev.parent = get_device(dev);
+ spi_slave_set_devdata(slave, &slave[1]);
+
+ return slave;
+}
+EXPORT_SYMBOL_GPL(spi_alloc_slave);
+
+
+
+/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
* Context: can sleep
@@ -507,7 +705,8 @@ int spi_register_master(struct spi_master *master)
status = device_add(&master->dev);
if (status < 0)
goto done;
- dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
+
+ dev_dbg(dev, "spi_register_master() : %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");
/* populate children from any spi device tables */
@@ -518,6 +717,69 @@ done:
}
EXPORT_SYMBOL_GPL(spi_register_master);
+/**
+* spi_register_slave - register SPI slave controller
+* @master: initialized master, originally from spi_alloc_slave()
+* Context: can sleep
+*
+* SPI slave controllers connect to their drivers using some non-SPI bus,
+* such as the platform bus. The final stage of probe() in that code
+* includes calling spi_register_slave() to hook up to this SPI bus glue.
+*
+* SPI controllers use board specific (often SOC specific) bus numbers,
+* and board-specific addressing for SPI devices combines those numbers
+* with chip select numbers. Since SPI does not directly support dynamic
+* device identification, boards need configuration tables telling which
+* chip is at which address.
+*
+* This must be called from context that can sleep. It returns zero on
+* success, else a negative error code (dropping the slave's refcount).
+* After a successful return, the caller is responsible for calling
+* spi_unregister_slave().
+*/
+int spi_register_slave(struct spi_slave *slave)
+{
+ static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
+ struct device *dev = slave->dev.parent;
+ int status = -ENODEV;
+ int dynamic = 0;
+
+ if (!dev)
+ return -ENODEV;
+
+ /* even if it's just one always-selected device, there must
+ * be at least one chipselect
+ */
+ if (slave->num_chipselect == 0)
+ return -EINVAL;
+
+ /* convention: dynamically assigned bus IDs count down from the max */
+ if (slave->bus_num < 0) {
+ /* FIXME switch to an IDR based scheme, something like
+ * I2C now uses, so we can't run out of "dynamic" IDs
+ */
+ slave->bus_num = atomic_dec_return(&dyn_bus_id);
+ dynamic = 1;
+ }
+
+ /* register the device, then userspace will see it.
+ * registration fails if the bus ID is in use.
+ */
+ dev_set_name(&slave->dev, "spi%u", slave->bus_num);
+ status = device_add(&slave->dev);
+ if (status < 0)
+ goto done;
+
+ dev_dbg(dev, "registered slave %s%s\n", dev_name(&slave->dev),
+ dynamic ? " (dynamic)" : "");
+
+ /* populate children from any spi device tables */
+ spi_slave_scan_boardinfo(slave);
+ status = 0;
+done:
+ return status;
+}
+EXPORT_SYMBOL_GPL(spi_register_slave);
static int __unregister(struct device *dev, void *master_dev)
{
@@ -547,6 +809,27 @@ void spi_unregister_master(struct spi_master *master)
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
+/**
+* spi_unregister_slave - unregister SPI slave controller
+* @master: the slave being unregistered
+* Context: can sleep
+*
+* This call is used only by SPI slave controller drivers, which are the
+* only ones directly touching chip registers.
+*
+* This must be called from context that can sleep.
+*/
+void spi_unregister_slave(struct spi_slave *slave)
+{
+ int dummy;
+
+ dummy = device_for_each_child(slave->dev.parent, &slave->dev,
+ __unregister);
+ device_unregister(&slave->dev);
+}
+EXPORT_SYMBOL_GPL(spi_unregister_slave);
+
+
static int __spi_master_match(struct device *dev, void *data)
{
struct spi_master *m;
@@ -626,6 +909,18 @@ int spi_sync(struct spi_device *spi, struct spi_message *message)
}
EXPORT_SYMBOL_GPL(spi_sync);
+/* spi_transfer_async - Wraper function to allow spi_async to expose to
+* user protocol drivers for modem handshaking
+*/
+
+int spi_transfer_async(struct spi_device *spi, struct spi_message *message)
+{
+ int status;
+ status = spi_async(spi, message);
+ return status;
+}
+EXPORT_SYMBOL_GPL(spi_transfer_async);
+
/* portable code must never pass more than 32 bytes */
#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES)
@@ -724,6 +1019,12 @@ static int __init spi_init(void)
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
+
+ status = class_register(&spi_slave_class);
+
+ if (status < 0)
+ goto err2;
+
return 0;
err2:
@@ -743,4 +1044,3 @@ err0:
* include needing to have boardinfo data structures be much more public.
*/
postcore_initcall(spi_init);
-
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index a0faa18..5845bb1 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -22,15 +22,18 @@
#include <linux/device.h>
/*
- * INTERFACES between SPI master-side drivers and SPI infrastructure.
- * (There's no SPI slave support for Linux yet...)
+ * INTERFACES between SPI Master/Slave side drivers and
+ * SPI infrastructure.
+ * SPI Slave Support added : It uses few new APIs and
+ * a new spi_slave struct
*/
extern struct bus_type spi_bus_type;
/**
* struct spi_device - Master side proxy for an SPI slave device
* @dev: Driver model representation of the device.
- * @master: SPI controller used with the device.
+ * @master: SPI Master controller used with the device.
+ * @slave: SPI Slave Controller used with the device
* @max_speed_hz: Maximum clock rate to be used with this chip
* (on this board); may be changed by the device's driver.
* The spi_transfer.speed_hz can override this for each transfer.
@@ -67,6 +70,7 @@ extern struct bus_type spi_bus_type;
struct spi_device {
struct device dev;
struct spi_master *master;
+ struct spi_slave *slave;
u32 max_speed_hz;
u8 chip_select;
u8 mode;
@@ -140,7 +144,6 @@ static inline void *spi_get_drvdata(struct spi_device *spi)
struct spi_message;
-
/**
* struct spi_driver - Host side "protocol" driver
* @probe: Binds this driver to the spi device. Drivers can verify
@@ -279,16 +282,56 @@ struct spi_master {
void (*cleanup)(struct spi_device *spi);
};
+/**
+ * struct spi_slave - interface to SPI Slave Controller
+ * @dev: device interface to this driver
+ * @bus_num: board-specific (and often SOC-specific) identifier for a
+ * given SPI controller.
+ * @num_chipselect: chipselects are used to distinguish individual
+ * SPI slaves, and are numbered from zero to num_chipselects.
+ * each slave has a chipselect signal, but it's common that not
+ * every chipselect is connected to a slave.
+ * @setup: updates the device mode and clocking records used by a
+ * device's SPI controller; protocol code may call this. This
+ * must fail if an unrecognized or unsupported mode is requested.
+ * It's always safe to call this unless transfers are pending on
+ * the device whose settings are being modified.
+ * @transfer: adds a message to the controller's transfer queue.
+ * @cleanup: frees controller-specific state
+ */
+struct spi_slave {
+ struct device dev;
+ s16 bus_num;
+ u16 num_chipselect;
+
+ int (*setup)(struct spi_device *spi);
+
+ int (*transfer)(struct spi_device *spi,
+ struct spi_message *mesg);
+
+ void (*cleanup)(struct spi_device *spi);
+};
+
static inline void *spi_master_get_devdata(struct spi_master *master)
{
return dev_get_drvdata(&master->dev);
}
+static inline void *spi_slave_get_devdata(struct spi_slave *slave)
+{
+ return dev_get_drvdata(&slave->dev);
+}
+
static inline void spi_master_set_devdata(struct spi_master *master, void *data)
{
dev_set_drvdata(&master->dev, data);
}
+static inline void spi_slave_set_devdata(struct spi_slave *slave, void *data)
+{
+ dev_set_drvdata(&slave->dev, data);
+}
+
static inline struct spi_master *spi_master_get(struct spi_master *master)
{
if (!master || !get_device(&master->dev))
@@ -296,20 +339,42 @@ static inline struct spi_master *spi_master_get(struct spi_master *master)
return master;
}
+static inline struct spi_slave *spi_slave_get(struct spi_slave *slave)
+{
+ if (!slave || !get_device(&slave->dev))
+ return NULL;
+ return slave;
+}
+
static inline void spi_master_put(struct spi_master *master)
{
if (master)
put_device(&master->dev);
}
+static inline void spi_slave_put(struct spi_slave *slave)
+{
+ if (slave)
+ put_device(&slave->dev);
+}
+
/* the spi driver core manages memory for the spi_master classdev */
extern struct spi_master *
spi_alloc_master(struct device *host, unsigned size);
+extern struct spi_slave *
+spi_alloc_slave(struct device *host, unsigned size);
+
+
extern int spi_register_master(struct spi_master *master);
+
+extern int spi_register_slave(struct spi_slave *slave);
+
extern void spi_unregister_master(struct spi_master *master);
+extern void spi_unregister_slave(struct spi_slave *slave);
+
extern struct spi_master *spi_busnum_to_master(u16 busnum);
/*---------------------------------------------------------------------------*/
@@ -544,10 +609,12 @@ static inline void spi_message_free(struct spi_message *m)
static inline int
spi_setup(struct spi_device *spi)
{
- return spi->master->setup(spi);
+ if (spi->master)
+ return spi->master->setup(spi);
+ else
+ return spi->slave->setup(spi);
}
-
/**
* spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged
@@ -581,7 +648,10 @@ static inline int
spi_async(struct spi_device *spi, struct spi_message *message)
{
message->spi = spi;
- return spi->master->transfer(spi, message);
+ if (spi->master)
+ return spi->master->transfer(spi, message); /* Master */
+ else
+ return spi->slave->transfer(spi, message); /* Slave */
}
/*---------------------------------------------------------------------------*/
@@ -593,6 +663,11 @@ spi_async(struct spi_device *spi, struct spi_message *message)
extern int spi_sync(struct spi_device *spi, struct spi_message *message);
+/* spi_transfer_async() exposes spi_async() functionality */
+extern int spi_transfer_async(struct spi_device *spi,
+ struct spi_message *message);
+
+
/**
* spi_write - SPI synchronous write
* @spi: device to which data will be written
@@ -801,12 +876,23 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
extern struct spi_device *
spi_alloc_device(struct spi_master *master);
+extern struct spi_device *
+spi_alloc_slave_device(struct spi_slave *slave);
+
extern int
spi_add_device(struct spi_device *spi);
+extern int
+spi_add_slave_device(struct spi_device *spi);
+
+
extern struct spi_device *
spi_new_device(struct spi_master *, struct spi_board_info *);
+extern struct spi_device *
+spi_slave_new_device(struct spi_slave *, struct spi_board_info *);
+
+
static inline void
spi_unregister_device(struct spi_device *spi)
{
--
1.5.4.3
------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables unlimited
royalty-free distribution of the report engine for externally facing
server and web deployment.
http://p.sf.net/sfu/businessobjects
next reply other threads:[~2009-06-12 17:44 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-06-12 17:44 Ken Mills [this message]
2009-07-03 1:45 ` [PATCH] This adds support for SPI slave controller drivers David Brownell
2009-07-07 19:57 ` Linus Walleij
-- strict thread matches above, loose matches on Subject: below --
2009-06-02 3:51 Ken Mills
2009-06-12 3:05 ` Baruch Siach
2009-06-12 20:12 ` Linus Walleij
2009-07-07 19:58 ` Fwd: " Linus Walleij
[not found] ` <63386a3d0907071258t695fdbaerd8485c58f27dcd00-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2009-07-15 16:24 ` Mills, Ken K
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1244828653.3513.16.camel@ubuntu-vmware \
--to=ken.k.mills-ral2jqcrhueavxtiumwx3w@public.gmane.org \
--cc=dbrownell-Rn4VEauK+AKRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
--cc=spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.