[PATCH] spi: add spi_driver to SPI framework
This is a refresh of the "Simple SPI Framework" found in 2.6.15-rc3-mm1 which makes the following changes: * There's now a "struct spi_driver". This increase the footprint of the core a bit, since it now includes code to do what the driver core was previously handling directly. Documentation and comments were updated to match. * spi_alloc_master() now does class_device_initialize(), so it can at least be refcounted before spi_register_master(). To match, spi_register_master() switched over to class_device_add(). * States explicitly that after transfer errors, spi_devices will be deselected. We want fault recovery procedures to work the same for all controller drivers. * Minor tweaks: controller_data no longer points to readonly data; prevent some potential cast-from-null bugs with container_of calls; clarifies some existing kerneldoc, And a few small cleanups. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
1d6432fe10
commit
b885244eb2
|
@ -1,18 +1,19 @@
|
||||||
Overview of Linux kernel SPI support
|
Overview of Linux kernel SPI support
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
22-Nov-2005
|
02-Dec-2005
|
||||||
|
|
||||||
What is SPI?
|
What is SPI?
|
||||||
------------
|
------------
|
||||||
The "Serial Peripheral Interface" (SPI) is a four-wire point-to-point
|
The "Serial Peripheral Interface" (SPI) is a synchronous four wire serial
|
||||||
serial link used to connect microcontrollers to sensors and memory.
|
link used to connect microcontrollers to sensors, memory, and peripherals.
|
||||||
|
|
||||||
The three signal wires hold a clock (SCLK, often on the order of 10 MHz),
|
The three signal wires hold a clock (SCLK, often on the order of 10 MHz),
|
||||||
and parallel data lines with "Master Out, Slave In" (MOSI) or "Master In,
|
and parallel data lines with "Master Out, Slave In" (MOSI) or "Master In,
|
||||||
Slave Out" (MISO) signals. (Other names are also used.) There are four
|
Slave Out" (MISO) signals. (Other names are also used.) There are four
|
||||||
clocking modes through which data is exchanged; mode-0 and mode-3 are most
|
clocking modes through which data is exchanged; mode-0 and mode-3 are most
|
||||||
commonly used.
|
commonly used. Each clock cycle shifts data out and data in; the clock
|
||||||
|
doesn't cycle except when there is data to shift.
|
||||||
|
|
||||||
SPI masters may use a "chip select" line to activate a given SPI slave
|
SPI masters may use a "chip select" line to activate a given SPI slave
|
||||||
device, so those three signal wires may be connected to several chips
|
device, so those three signal wires may be connected to several chips
|
||||||
|
@ -79,11 +80,18 @@ The <linux/spi/spi.h> header file includes kerneldoc, as does the
|
||||||
main source code, and you should certainly read that. This is just
|
main source code, and you should certainly read that. This is just
|
||||||
an overview, so you get the big picture before the details.
|
an overview, so you get the big picture before the details.
|
||||||
|
|
||||||
|
SPI requests always go into I/O queues. Requests for a given SPI device
|
||||||
|
are always executed in FIFO order, and complete asynchronously through
|
||||||
|
completion callbacks. There are also some simple synchronous wrappers
|
||||||
|
for those calls, including ones for common transaction types like writing
|
||||||
|
a command and then reading its response.
|
||||||
|
|
||||||
There are two types of SPI driver, here called:
|
There are two types of SPI driver, here called:
|
||||||
|
|
||||||
Controller drivers ... these are often built in to System-On-Chip
|
Controller drivers ... these are often built in to System-On-Chip
|
||||||
processors, and often support both Master and Slave roles.
|
processors, and often support both Master and Slave roles.
|
||||||
These drivers touch hardware registers and may use DMA.
|
These drivers touch hardware registers and may use DMA.
|
||||||
|
Or they can be PIO bitbangers, needing just GPIO pins.
|
||||||
|
|
||||||
Protocol drivers ... these pass messages through the controller
|
Protocol drivers ... these pass messages through the controller
|
||||||
driver to communicate with a Slave or Master device on the
|
driver to communicate with a Slave or Master device on the
|
||||||
|
@ -116,11 +124,6 @@ shows up in sysfs in several locations:
|
||||||
managing bus "B". All the spiB.* devices share the same
|
managing bus "B". All the spiB.* devices share the same
|
||||||
physical SPI bus segment, with SCLK, MOSI, and MISO.
|
physical SPI bus segment, with SCLK, MOSI, and MISO.
|
||||||
|
|
||||||
The basic I/O primitive submits an asynchronous message to an I/O queue
|
|
||||||
maintained by the controller driver. A completion callback is issued
|
|
||||||
asynchronously when the data transfer(s) in that message completes.
|
|
||||||
There are also some simple synchronous wrappers for those calls.
|
|
||||||
|
|
||||||
|
|
||||||
How does board-specific init code declare SPI devices?
|
How does board-specific init code declare SPI devices?
|
||||||
------------------------------------------------------
|
------------------------------------------------------
|
||||||
|
@ -263,33 +266,40 @@ would just be another kernel driver, probably offering some lowlevel
|
||||||
access through aio_read(), aio_write(), and ioctl() calls and using the
|
access through aio_read(), aio_write(), and ioctl() calls and using the
|
||||||
standard userspace sysfs mechanisms to bind to a given SPI device.
|
standard userspace sysfs mechanisms to bind to a given SPI device.
|
||||||
|
|
||||||
SPI protocol drivers are normal device drivers, with no more wrapper
|
SPI protocol drivers somewhat resemble platform device drivers:
|
||||||
than needed by platform devices:
|
|
||||||
|
static struct spi_driver CHIP_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "CHIP",
|
||||||
|
.bus = &spi_bus_type,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
},
|
||||||
|
|
||||||
static struct device_driver CHIP_driver = {
|
|
||||||
.name = "CHIP",
|
|
||||||
.bus = &spi_bus_type,
|
|
||||||
.probe = CHIP_probe,
|
.probe = CHIP_probe,
|
||||||
.remove = __exit_p(CHIP_remove),
|
.remove = __devexit_p(CHIP_remove),
|
||||||
.suspend = CHIP_suspend,
|
.suspend = CHIP_suspend,
|
||||||
.resume = CHIP_resume,
|
.resume = CHIP_resume,
|
||||||
};
|
};
|
||||||
|
|
||||||
The SPI core will autmatically attempt to bind this driver to any SPI
|
The driver core will autmatically attempt to bind this driver to any SPI
|
||||||
device whose board_info gave a modalias of "CHIP". Your probe() code
|
device whose board_info gave a modalias of "CHIP". Your probe() code
|
||||||
might look like this unless you're creating a class_device:
|
might look like this unless you're creating a class_device:
|
||||||
|
|
||||||
static int __init CHIP_probe(struct device *dev)
|
static int __devinit CHIP_probe(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct spi_device *spi = to_spi_device(dev);
|
|
||||||
struct CHIP *chip;
|
struct CHIP *chip;
|
||||||
struct CHIP_platform_data *pdata = dev->platform_data;
|
struct CHIP_platform_data *pdata;
|
||||||
|
|
||||||
|
/* assuming the driver requires board-specific data: */
|
||||||
|
pdata = &spi->dev.platform_data;
|
||||||
|
if (!pdata)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
/* get memory for driver's per-chip state */
|
/* get memory for driver's per-chip state */
|
||||||
chip = kzalloc(sizeof *chip, GFP_KERNEL);
|
chip = kzalloc(sizeof *chip, GFP_KERNEL);
|
||||||
if (!chip)
|
if (!chip)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
dev_set_drvdata(dev, chip);
|
dev_set_drvdata(&spi->dev, chip);
|
||||||
|
|
||||||
... etc
|
... etc
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -328,6 +338,8 @@ the driver guarantees that it won't submit any more such messages.
|
||||||
- The basic I/O primitive is spi_async(). Async requests may be
|
- The basic I/O primitive is spi_async(). Async requests may be
|
||||||
issued in any context (irq handler, task, etc) and completion
|
issued in any context (irq handler, task, etc) and completion
|
||||||
is reported using a callback provided with the message.
|
is reported using a callback provided with the message.
|
||||||
|
After any detected error, the chip is deselected and processing
|
||||||
|
of that spi_message is aborted.
|
||||||
|
|
||||||
- There are also synchronous wrappers like spi_sync(), and wrappers
|
- There are also synchronous wrappers like spi_sync(), and wrappers
|
||||||
like spi_read(), spi_write(), and spi_write_then_read(). These
|
like spi_read(), spi_write(), and spi_write_then_read(). These
|
||||||
|
|
|
@ -26,13 +26,9 @@
|
||||||
#include <linux/spi/spi.h>
|
#include <linux/spi/spi.h>
|
||||||
|
|
||||||
|
|
||||||
/* SPI bustype and spi_master class are registered during early boot,
|
/* SPI bustype and spi_master class are registered after board init code
|
||||||
* usually before board init code provides the SPI device tables, and
|
* provides the SPI device tables, ensuring that both are present by the
|
||||||
* are available later when driver init code needs them.
|
* time controller driver registration causes spi_devices to "enumerate".
|
||||||
*
|
|
||||||
* Drivers for SPI devices started out like those for platform bus
|
|
||||||
* devices. But both have changed in 2.6.15; maybe this should get
|
|
||||||
* an "spi_driver" structure at some point (not currently needed)
|
|
||||||
*/
|
*/
|
||||||
static void spidev_release(struct device *dev)
|
static void spidev_release(struct device *dev)
|
||||||
{
|
{
|
||||||
|
@ -83,10 +79,7 @@ static int spi_uevent(struct device *dev, char **envp, int num_envp,
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
|
||||||
/* Suspend/resume in "struct device_driver" don't really need that
|
/*
|
||||||
* strange third parameter, so we just make it a constant and expect
|
|
||||||
* SPI drivers to ignore it just like most platform drivers do.
|
|
||||||
*
|
|
||||||
* NOTE: the suspend() method for an spi_master controller driver
|
* NOTE: the suspend() method for an spi_master controller driver
|
||||||
* should verify that all its child devices are marked as suspended;
|
* should verify that all its child devices are marked as suspended;
|
||||||
* suspend requests delivered through sysfs power/state files don't
|
* suspend requests delivered through sysfs power/state files don't
|
||||||
|
@ -94,13 +87,14 @@ static int spi_uevent(struct device *dev, char **envp, int num_envp,
|
||||||
*/
|
*/
|
||||||
static int spi_suspend(struct device *dev, pm_message_t message)
|
static int spi_suspend(struct device *dev, pm_message_t message)
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
|
struct spi_driver *drv = to_spi_driver(dev->driver);
|
||||||
|
|
||||||
if (!dev->driver || !dev->driver->suspend)
|
if (!drv || !drv->suspend)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* suspend will stop irqs and dma; no more i/o */
|
/* suspend will stop irqs and dma; no more i/o */
|
||||||
value = dev->driver->suspend(dev, message);
|
value = drv->suspend(to_spi_device(dev), message);
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
dev->power.power_state = message;
|
dev->power.power_state = message;
|
||||||
return value;
|
return value;
|
||||||
|
@ -108,13 +102,14 @@ static int spi_suspend(struct device *dev, pm_message_t message)
|
||||||
|
|
||||||
static int spi_resume(struct device *dev)
|
static int spi_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
|
struct spi_driver *drv = to_spi_driver(dev->driver);
|
||||||
|
|
||||||
if (!dev->driver || !dev->driver->resume)
|
if (!drv || !drv->resume)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* resume may restart the i/o queue */
|
/* resume may restart the i/o queue */
|
||||||
value = dev->driver->resume(dev);
|
value = drv->resume(to_spi_device(dev));
|
||||||
if (value == 0)
|
if (value == 0)
|
||||||
dev->power.power_state = PMSG_ON;
|
dev->power.power_state = PMSG_ON;
|
||||||
return value;
|
return value;
|
||||||
|
@ -135,6 +130,41 @@ struct bus_type spi_bus_type = {
|
||||||
};
|
};
|
||||||
EXPORT_SYMBOL_GPL(spi_bus_type);
|
EXPORT_SYMBOL_GPL(spi_bus_type);
|
||||||
|
|
||||||
|
|
||||||
|
static int spi_drv_probe(struct device *dev)
|
||||||
|
{
|
||||||
|
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||||
|
|
||||||
|
return sdrv->probe(to_spi_device(dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int spi_drv_remove(struct device *dev)
|
||||||
|
{
|
||||||
|
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||||
|
|
||||||
|
return sdrv->remove(to_spi_device(dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void spi_drv_shutdown(struct device *dev)
|
||||||
|
{
|
||||||
|
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
|
||||||
|
|
||||||
|
sdrv->shutdown(to_spi_device(dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
/* SPI devices should normally not be created by SPI device drivers; that
|
/* SPI devices should normally not be created by SPI device drivers; that
|
||||||
|
@ -208,13 +238,15 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip)
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
dev_dbg(dev, "can't %s %s, status %d\n",
|
dev_dbg(dev, "can't %s %s, status %d\n",
|
||||||
"add", proxy->dev.bus_id, status);
|
"add", proxy->dev.bus_id, status);
|
||||||
fail:
|
goto fail;
|
||||||
class_device_put(&master->cdev);
|
|
||||||
kfree(proxy);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
|
dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id);
|
||||||
return proxy;
|
return proxy;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
class_device_put(&master->cdev);
|
||||||
|
kfree(proxy);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_new_device);
|
EXPORT_SYMBOL_GPL(spi_new_device);
|
||||||
|
|
||||||
|
@ -237,11 +269,11 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
||||||
{
|
{
|
||||||
struct boardinfo *bi;
|
struct boardinfo *bi;
|
||||||
|
|
||||||
bi = kmalloc (sizeof (*bi) + n * sizeof (*info), GFP_KERNEL);
|
bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
|
||||||
if (!bi)
|
if (!bi)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
bi->n_board_info = n;
|
bi->n_board_info = n;
|
||||||
memcpy(bi->board_info, info, n * sizeof (*info));
|
memcpy(bi->board_info, info, n * sizeof *info);
|
||||||
|
|
||||||
down(&board_lock);
|
down(&board_lock);
|
||||||
list_add_tail(&bi->list, &board_list);
|
list_add_tail(&bi->list, &board_list);
|
||||||
|
@ -330,6 +362,7 @@ spi_alloc_master(struct device *dev, unsigned size)
|
||||||
if (!master)
|
if (!master)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
class_device_initialize(&master->cdev);
|
||||||
master->cdev.class = &spi_master_class;
|
master->cdev.class = &spi_master_class;
|
||||||
master->cdev.dev = get_device(dev);
|
master->cdev.dev = get_device(dev);
|
||||||
class_set_devdata(&master->cdev, &master[1]);
|
class_set_devdata(&master->cdev, &master[1]);
|
||||||
|
@ -366,7 +399,7 @@ spi_register_master(struct spi_master *master)
|
||||||
/* convention: dynamically assigned bus IDs count down from the max */
|
/* convention: dynamically assigned bus IDs count down from the max */
|
||||||
if (master->bus_num == 0) {
|
if (master->bus_num == 0) {
|
||||||
master->bus_num = atomic_dec_return(&dyn_bus_id);
|
master->bus_num = atomic_dec_return(&dyn_bus_id);
|
||||||
dynamic = 0;
|
dynamic = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* register the device, then userspace will see it.
|
/* register the device, then userspace will see it.
|
||||||
|
@ -374,11 +407,9 @@ spi_register_master(struct spi_master *master)
|
||||||
*/
|
*/
|
||||||
snprintf(master->cdev.class_id, sizeof master->cdev.class_id,
|
snprintf(master->cdev.class_id, sizeof master->cdev.class_id,
|
||||||
"spi%u", master->bus_num);
|
"spi%u", master->bus_num);
|
||||||
status = class_device_register(&master->cdev);
|
status = class_device_add(&master->cdev);
|
||||||
if (status < 0) {
|
if (status < 0)
|
||||||
class_device_put(&master->cdev);
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
|
||||||
dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
|
dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
|
||||||
dynamic ? " (dynamic)" : "");
|
dynamic ? " (dynamic)" : "");
|
||||||
|
|
||||||
|
@ -491,6 +522,7 @@ static u8 *buf;
|
||||||
* This performs a half duplex MicroWire style transaction with the
|
* This performs a half duplex MicroWire style transaction with the
|
||||||
* device, sending txbuf and then reading rxbuf. The return value
|
* device, sending txbuf and then reading rxbuf. The return value
|
||||||
* is zero for success, else a negative errno status code.
|
* is zero for success, else a negative errno status code.
|
||||||
|
* This call may only be used from a context that may sleep.
|
||||||
*
|
*
|
||||||
* Parameters to this routine are always copied using a small buffer,
|
* Parameters to this routine are always copied using a small buffer,
|
||||||
* large transfers should use use spi_{async,sync}() calls with
|
* large transfers should use use spi_{async,sync}() calls with
|
||||||
|
@ -553,16 +585,38 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
|
||||||
|
|
||||||
static int __init spi_init(void)
|
static int __init spi_init(void)
|
||||||
{
|
{
|
||||||
buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
|
int status;
|
||||||
if (!buf)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
bus_register(&spi_bus_type);
|
buf = kmalloc(SPI_BUFSIZ, SLAB_KERNEL);
|
||||||
class_register(&spi_master_class);
|
if (!buf) {
|
||||||
|
status = -ENOMEM;
|
||||||
|
goto err0;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = bus_register(&spi_bus_type);
|
||||||
|
if (status < 0)
|
||||||
|
goto err1;
|
||||||
|
|
||||||
|
status = class_register(&spi_master_class);
|
||||||
|
if (status < 0)
|
||||||
|
goto err2;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err2:
|
||||||
|
bus_unregister(&spi_bus_type);
|
||||||
|
err1:
|
||||||
|
kfree(buf);
|
||||||
|
buf = NULL;
|
||||||
|
err0:
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* board_info is normally registered in arch_initcall(),
|
/* board_info is normally registered in arch_initcall(),
|
||||||
* but even essential drivers wait till later
|
* but even essential drivers wait till later
|
||||||
|
*
|
||||||
|
* REVISIT only boardinfo really needs static linking. the rest (device and
|
||||||
|
* driver registration) _could_ be dynamically linked (modular) ... costs
|
||||||
|
* include needing to have boardinfo data structures be much more public.
|
||||||
*/
|
*/
|
||||||
subsys_initcall(spi_init);
|
subsys_initcall(spi_init);
|
||||||
|
|
||||||
|
|
|
@ -20,13 +20,8 @@
|
||||||
#define __LINUX_SPI_H
|
#define __LINUX_SPI_H
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* INTERFACES between SPI master drivers and infrastructure
|
* INTERFACES between SPI master-side drivers and SPI infrastructure.
|
||||||
* (There's no SPI slave support for Linux yet...)
|
* (There's no SPI slave support for Linux yet...)
|
||||||
*
|
|
||||||
* A "struct device_driver" for an spi_device uses "spi_bus_type" and
|
|
||||||
* needs no special API wrappers (much like platform_bus). These drivers
|
|
||||||
* are bound to devices based on their names (much like platform_bus),
|
|
||||||
* and are available in dev->driver.
|
|
||||||
*/
|
*/
|
||||||
extern struct bus_type spi_bus_type;
|
extern struct bus_type spi_bus_type;
|
||||||
|
|
||||||
|
@ -46,8 +41,8 @@ extern struct bus_type spi_bus_type;
|
||||||
* @irq: Negative, or the number passed to request_irq() to receive
|
* @irq: Negative, or the number passed to request_irq() to receive
|
||||||
* interrupts from this device.
|
* interrupts from this device.
|
||||||
* @controller_state: Controller's runtime state
|
* @controller_state: Controller's runtime state
|
||||||
* @controller_data: Static board-specific definitions for controller, such
|
* @controller_data: Board-specific definitions for controller, such as
|
||||||
* as FIFO initialization parameters; from board_info.controller_data
|
* FIFO initialization parameters; from board_info.controller_data
|
||||||
*
|
*
|
||||||
* An spi_device is used to interchange data between an SPI slave
|
* An spi_device is used to interchange data between an SPI slave
|
||||||
* (usually a discrete chip) and CPU memory.
|
* (usually a discrete chip) and CPU memory.
|
||||||
|
@ -63,31 +58,32 @@ struct spi_device {
|
||||||
u32 max_speed_hz;
|
u32 max_speed_hz;
|
||||||
u8 chip_select;
|
u8 chip_select;
|
||||||
u8 mode;
|
u8 mode;
|
||||||
#define SPI_CPHA 0x01 /* clock phase */
|
#define SPI_CPHA 0x01 /* clock phase */
|
||||||
#define SPI_CPOL 0x02 /* clock polarity */
|
#define SPI_CPOL 0x02 /* clock polarity */
|
||||||
#define SPI_MODE_0 (0|0)
|
#define SPI_MODE_0 (0|0)
|
||||||
#define SPI_MODE_1 (0|SPI_CPHA)
|
#define SPI_MODE_1 (0|SPI_CPHA) /* (original MicroWire) */
|
||||||
#define SPI_MODE_2 (SPI_CPOL|0)
|
#define SPI_MODE_2 (SPI_CPOL|0)
|
||||||
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
|
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
|
||||||
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
|
#define SPI_CS_HIGH 0x04 /* chipselect active high? */
|
||||||
u8 bits_per_word;
|
u8 bits_per_word;
|
||||||
int irq;
|
int irq;
|
||||||
void *controller_state;
|
void *controller_state;
|
||||||
const void *controller_data;
|
void *controller_data;
|
||||||
const char *modalias;
|
const char *modalias;
|
||||||
|
|
||||||
// likely need more hooks for more protocol options affecting how
|
// likely need more hooks for more protocol options affecting how
|
||||||
// the controller talks to its chips, like:
|
// the controller talks to each chip, like:
|
||||||
// - bit order (default is wordwise msb-first)
|
// - bit order (default is wordwise msb-first)
|
||||||
// - memory packing (12 bit samples into low bits, others zeroed)
|
// - memory packing (12 bit samples into low bits, others zeroed)
|
||||||
// - priority
|
// - priority
|
||||||
|
// - drop chipselect after each word
|
||||||
// - chipselect delays
|
// - chipselect delays
|
||||||
// - ...
|
// - ...
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct spi_device *to_spi_device(struct device *dev)
|
static inline struct spi_device *to_spi_device(struct device *dev)
|
||||||
{
|
{
|
||||||
return container_of(dev, struct spi_device, dev);
|
return dev ? container_of(dev, struct spi_device, dev) : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* most drivers won't need to care about device refcounting */
|
/* most drivers won't need to care about device refcounting */
|
||||||
|
@ -117,12 +113,38 @@ static inline void spi_set_ctldata(struct spi_device *spi, void *state)
|
||||||
struct spi_message;
|
struct spi_message;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct spi_driver {
|
||||||
|
int (*probe)(struct spi_device *spi);
|
||||||
|
int (*remove)(struct spi_device *spi);
|
||||||
|
void (*shutdown)(struct spi_device *spi);
|
||||||
|
int (*suspend)(struct spi_device *spi, pm_message_t mesg);
|
||||||
|
int (*resume)(struct spi_device *spi);
|
||||||
|
struct device_driver driver;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct spi_driver *to_spi_driver(struct device_driver *drv)
|
||||||
|
{
|
||||||
|
return drv ? container_of(drv, struct spi_driver, driver) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int spi_register_driver(struct spi_driver *sdrv);
|
||||||
|
|
||||||
|
static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
||||||
|
{
|
||||||
|
if (!sdrv)
|
||||||
|
return;
|
||||||
|
driver_unregister(&sdrv->driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct spi_master - interface to SPI master controller
|
* struct spi_master - interface to SPI master controller
|
||||||
* @cdev: class interface to this driver
|
* @cdev: class interface to this driver
|
||||||
* @bus_num: board-specific (and often SOC-specific) identifier for a
|
* @bus_num: board-specific (and often SOC-specific) identifier for a
|
||||||
* given SPI controller.
|
* given SPI controller.
|
||||||
* @num_chipselects: chipselects are used to distinguish individual
|
* @num_chipselect: chipselects are used to distinguish individual
|
||||||
* SPI slaves, and are numbered from zero to num_chipselects.
|
* SPI slaves, and are numbered from zero to num_chipselects.
|
||||||
* each slave has a chipselect signal, but it's common that not
|
* each slave has a chipselect signal, but it's common that not
|
||||||
* every chipselect is connected to a slave.
|
* every chipselect is connected to a slave.
|
||||||
|
@ -275,7 +297,8 @@ struct spi_transfer {
|
||||||
* addresses for each transfer buffer
|
* addresses for each transfer buffer
|
||||||
* @complete: called to report transaction completions
|
* @complete: called to report transaction completions
|
||||||
* @context: the argument to complete() when it's called
|
* @context: the argument to complete() when it's called
|
||||||
* @actual_length: how many bytes were transferd
|
* @actual_length: the total number of bytes that were transferred in all
|
||||||
|
* successful segments
|
||||||
* @status: zero for success, else negative errno
|
* @status: zero for success, else negative errno
|
||||||
* @queue: for use by whichever driver currently owns the message
|
* @queue: for use by whichever driver currently owns the message
|
||||||
* @state: for use by whichever driver currently owns the message
|
* @state: for use by whichever driver currently owns the message
|
||||||
|
@ -295,7 +318,7 @@ struct spi_message {
|
||||||
*
|
*
|
||||||
* Some controller drivers (message-at-a-time queue processing)
|
* Some controller drivers (message-at-a-time queue processing)
|
||||||
* could provide that as their default scheduling algorithm. But
|
* could provide that as their default scheduling algorithm. But
|
||||||
* others (with multi-message pipelines) would need a flag to
|
* others (with multi-message pipelines) could need a flag to
|
||||||
* tell them about such special cases.
|
* tell them about such special cases.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -346,6 +369,13 @@ spi_setup(struct spi_device *spi)
|
||||||
* FIFO order, messages may go to different devices in other orders.
|
* FIFO order, messages may go to different devices in other orders.
|
||||||
* Some device might be higher priority, or have various "hard" access
|
* Some device might be higher priority, or have various "hard" access
|
||||||
* time requirements, for example.
|
* time requirements, for example.
|
||||||
|
*
|
||||||
|
* On detection of any fault during the transfer, processing of
|
||||||
|
* the entire message is aborted, and the device is deselected.
|
||||||
|
* Until returning from the associated message completion callback,
|
||||||
|
* no other spi_message queued to that device will be processed.
|
||||||
|
* (This rule applies equally to all the synchronous transfer calls,
|
||||||
|
* which are wrappers around this core asynchronous primitive.)
|
||||||
*/
|
*/
|
||||||
static inline int
|
static inline int
|
||||||
spi_async(struct spi_device *spi, struct spi_message *message)
|
spi_async(struct spi_device *spi, struct spi_message *message)
|
||||||
|
@ -484,12 +514,12 @@ struct spi_board_info {
|
||||||
* "modalias" is normally the driver name.
|
* "modalias" is normally the driver name.
|
||||||
*
|
*
|
||||||
* platform_data goes to spi_device.dev.platform_data,
|
* platform_data goes to spi_device.dev.platform_data,
|
||||||
* controller_data goes to spi_device.platform_data,
|
* controller_data goes to spi_device.controller_data,
|
||||||
* irq is copied too
|
* irq is copied too
|
||||||
*/
|
*/
|
||||||
char modalias[KOBJ_NAME_LEN];
|
char modalias[KOBJ_NAME_LEN];
|
||||||
const void *platform_data;
|
const void *platform_data;
|
||||||
const void *controller_data;
|
void *controller_data;
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
/* slower signaling on noisy or low voltage boards */
|
/* slower signaling on noisy or low voltage boards */
|
||||||
|
@ -525,9 +555,8 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
|
||||||
|
|
||||||
|
|
||||||
/* If you're hotplugging an adapter with devices (parport, usb, etc)
|
/* If you're hotplugging an adapter with devices (parport, usb, etc)
|
||||||
* use spi_new_device() to describe each device. You can also call
|
* use spi_new_device() to describe each device. You would then call
|
||||||
* spi_unregister_device() to get start making that device vanish,
|
* spi_unregister_device() to start making that device vanish.
|
||||||
* but normally that would be handled by spi_unregister_master().
|
|
||||||
*/
|
*/
|
||||||
extern struct spi_device *
|
extern struct spi_device *
|
||||||
spi_new_device(struct spi_master *, struct spi_board_info *);
|
spi_new_device(struct spi_master *, struct spi_board_info *);
|
||||||
|
|
Loading…
Reference in New Issue