Hi Ken, Your patches are very interesting.
Unfortunately, your email client (Evolution?) has broken long lines in your patches. Please resend them. You may consult Documentation/email-clients.txt. baruch On Mon, Jun 01, 2009 at 08:51:37PM -0700, Ken Mills wrote: > This patch adds a new API to support slave SPI controller drivers. > > Signed-off-by: Ken Mills <[email protected]> > --- > 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 > _______________________________________________ > spi-devel-general mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/spi-devel-general -- ~. .~ Tk Open Systems =}------------------------------------------------ooO--U--Ooo------------{= - [email protected] - tel: +972.2.679.5364, http://www.tkos.co.il - ------------------------------------------------------------------------------ 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 _______________________________________________ spi-devel-general mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/spi-devel-general
