aboutsummaryrefslogtreecommitdiff
path: root/Documentation/spi
diff options
context:
space:
mode:
Diffstat (limited to 'Documentation/spi')
-rw-r--r--Documentation/spi/.gitignore2
-rw-r--r--Documentation/spi/00-INDEX22
-rw-r--r--Documentation/spi/Makefile11
-rw-r--r--Documentation/spi/ep93xx_spi105
-rw-r--r--Documentation/spi/pxa2xx47
-rw-r--r--Documentation/spi/spi-lm70llp12
-rw-r--r--Documentation/spi/spi-sc18is60236
-rw-r--r--Documentation/spi/spi-summary110
-rw-r--r--Documentation/spi/spidev174
-rw-r--r--Documentation/spi/spidev_fdx.c158
-rw-r--r--Documentation/spi/spidev_test.c59
11 files changed, 519 insertions, 217 deletions
diff --git a/Documentation/spi/.gitignore b/Documentation/spi/.gitignore
new file mode 100644
index 00000000000..4280576397e
--- /dev/null
+++ b/Documentation/spi/.gitignore
@@ -0,0 +1,2 @@
+spidev_fdx
+spidev_test
diff --git a/Documentation/spi/00-INDEX b/Documentation/spi/00-INDEX
new file mode 100644
index 00000000000..a128fa83551
--- /dev/null
+++ b/Documentation/spi/00-INDEX
@@ -0,0 +1,22 @@
+00-INDEX
+ - this file.
+Makefile
+ - Makefile for the example sourcefiles.
+butterfly
+ - AVR Butterfly SPI driver overview and pin configuration.
+ep93xx_spi
+ - Basic EP93xx SPI driver configuration.
+pxa2xx
+ - PXA2xx SPI master controller build by spi_message fifo wq
+spidev
+ - Intro to the userspace API for spi devices
+spidev_fdx.c
+ - spidev example file
+spi-lm70llp
+ - Connecting an LM70-LLP sensor to the kernel via the SPI subsys.
+spi-sc18is602
+ - NXP SC18IS602/603 I2C-bus to SPI bridge
+spi-summary
+ - (Linux) SPI overview. If unsure about SPI or SPI in Linux, start here.
+spidev_test.c
+ - SPI testing utility.
diff --git a/Documentation/spi/Makefile b/Documentation/spi/Makefile
new file mode 100644
index 00000000000..a5b03c88bea
--- /dev/null
+++ b/Documentation/spi/Makefile
@@ -0,0 +1,11 @@
+# kbuild trick to avoid linker error. Can be omitted if a module is built.
+obj- := dummy.o
+
+# List of programs to build
+hostprogs-y := spidev_test spidev_fdx
+
+# Tell kbuild to always build the programs
+always := $(hostprogs-y)
+
+HOSTCFLAGS_spidev_test.o += -I$(objtree)/usr/include
+HOSTCFLAGS_spidev_fdx.o += -I$(objtree)/usr/include
diff --git a/Documentation/spi/ep93xx_spi b/Documentation/spi/ep93xx_spi
new file mode 100644
index 00000000000..832ddce6e5f
--- /dev/null
+++ b/Documentation/spi/ep93xx_spi
@@ -0,0 +1,105 @@
+Cirrus EP93xx SPI controller driver HOWTO
+=========================================
+
+ep93xx_spi driver brings SPI master support for EP93xx SPI controller. Chip
+selects are implemented with GPIO lines.
+
+NOTE: If possible, don't use SFRMOUT (SFRM1) signal as a chip select. It will
+not work correctly (it cannot be controlled by software). Use GPIO lines
+instead.
+
+Sample configuration
+====================
+
+Typically driver configuration is done in platform board files (the files under
+arch/arm/mach-ep93xx/*.c). In this example we configure MMC over SPI through
+this driver on TS-7260 board. You can adapt the code to suit your needs.
+
+This example uses EGPIO9 as SD/MMC card chip select (this is wired in DIO1
+header on the board).
+
+You need to select CONFIG_MMC_SPI to use mmc_spi driver.
+
+arch/arm/mach-ep93xx/ts72xx.c:
+
+...
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+
+#include <linux/platform_data/spi-ep93xx.h>
+
+/* this is our GPIO line used for chip select */
+#define MMC_CHIP_SELECT_GPIO EP93XX_GPIO_LINE_EGPIO9
+
+static int ts72xx_mmc_spi_setup(struct spi_device *spi)
+{
+ int err;
+
+ err = gpio_request(MMC_CHIP_SELECT_GPIO, spi->modalias);
+ if (err)
+ return err;
+
+ gpio_direction_output(MMC_CHIP_SELECT_GPIO, 1);
+
+ return 0;
+}
+
+static void ts72xx_mmc_spi_cleanup(struct spi_device *spi)
+{
+ gpio_set_value(MMC_CHIP_SELECT_GPIO, 1);
+ gpio_direction_input(MMC_CHIP_SELECT_GPIO);
+ gpio_free(MMC_CHIP_SELECT_GPIO);
+}
+
+static void ts72xx_mmc_spi_cs_control(struct spi_device *spi, int value)
+{
+ gpio_set_value(MMC_CHIP_SELECT_GPIO, value);
+}
+
+static struct ep93xx_spi_chip_ops ts72xx_mmc_spi_ops = {
+ .setup = ts72xx_mmc_spi_setup,
+ .cleanup = ts72xx_mmc_spi_cleanup,
+ .cs_control = ts72xx_mmc_spi_cs_control,
+};
+
+static struct spi_board_info ts72xx_spi_devices[] __initdata = {
+ {
+ .modalias = "mmc_spi",
+ .controller_data = &ts72xx_mmc_spi_ops,
+ /*
+ * We use 10 MHz even though the maximum is 7.4 MHz. The driver
+ * will limit it automatically to max. frequency.
+ */
+ .max_speed_hz = 10 * 1000 * 1000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ },
+};
+
+static struct ep93xx_spi_info ts72xx_spi_info = {
+ .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
+};
+
+static void __init ts72xx_init_machine(void)
+{
+ ...
+ ep93xx_register_spi(&ts72xx_spi_info, ts72xx_spi_devices,
+ ARRAY_SIZE(ts72xx_spi_devices));
+}
+
+The driver can use DMA for the transfers also. In this case ts72xx_spi_info
+becomes:
+
+static struct ep93xx_spi_info ts72xx_spi_info = {
+ .num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
+ .use_dma = true;
+};
+
+Note that CONFIG_EP93XX_DMA should be enabled as well.
+
+Thanks to
+=========
+Martin Guy, H. Hartley Sweeten and others who helped me during development of
+the driver. Simplemachines.it donated me a Sim.One board which I used testing
+the driver on EP9307.
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index f3853cc37bd..3352f97430e 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -2,7 +2,7 @@ PXA2xx SPI on SSP driver HOWTO
===================================================
This a mini howto on the pxa2xx_spi driver. The driver turns a PXA2xx
synchronous serial port into a SPI master controller
-(see Documentation/spi/spi_summary). The driver has the following features
+(see Documentation/spi/spi-summary). The driver has the following features
- Support for any PXA2xx SSP
- SSP PIO and SSP DMA data transfers.
@@ -19,18 +19,14 @@ Declaring PXA2xx Master Controllers
-----------------------------------
Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
"platform device". The master configuration is passed to the driver via a table
-found in include/asm-arm/arch-pxa/pxa2xx_spi.h:
+found in include/linux/spi/pxa2xx_spi.h:
struct pxa2xx_spi_master {
- enum pxa_ssp_type ssp_type;
u32 clock_enable;
u16 num_chipselect;
u8 enable_dma;
};
-The "pxa2xx_spi_master.ssp_type" field must have a value between 1 and 3 and
-informs the driver which features a particular SSP supports.
-
The "pxa2xx_spi_master.clock_enable" field is used to enable/disable the
corresponding SSP peripheral block in the "Clock Enable Register (CKEN"). See
the "PXA2xx Developer Manual" section "Clocks and Power Management".
@@ -61,7 +57,6 @@ static struct resource pxa_spi_nssp_resources[] = {
};
static struct pxa2xx_spi_master pxa_nssp_master_info = {
- .ssp_type = PXA25x_NSSP, /* Type of SSP */
.clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */
.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
.enable_dma = 1, /* Enables NSSP DMA */
@@ -90,13 +85,13 @@ Declaring Slave Devices
-----------------------
Typically each SPI slave (chip) is defined in the arch/.../mach-*/board-*.c
using the "spi_board_info" structure found in "linux/spi/spi.h". See
-"Documentation/spi/spi_summary" for additional information.
+"Documentation/spi/spi-summary" for additional information.
Each slave device attached to the PXA must provide slave specific configuration
information via the structure "pxa2xx_spi_chip" found in
-"include/asm-arm/arch-pxa/pxa2xx_spi.h". The pxa2xx_spi master controller driver
+"include/linux/spi/pxa2xx_spi.h". The pxa2xx_spi master controller driver
will uses the configuration whenever the driver communicates with the slave
-device.
+device. All fields are optional.
struct pxa2xx_spi_chip {
u8 tx_threshold;
@@ -112,14 +107,17 @@ used to configure the SSP hardware fifo. These fields are critical to the
performance of pxa2xx_spi driver and misconfiguration will result in rx
fifo overruns (especially in PIO mode transfers). Good default values are
- .tx_threshold = 12,
- .rx_threshold = 4,
+ .tx_threshold = 8,
+ .rx_threshold = 8,
+
+The range is 1 to 16 where zero indicates "use default".
The "pxa2xx_spi_chip.dma_burst_size" field is used to configure PXA2xx DMA
engine and is related the "spi_device.bits_per_word" field. Read and understand
the PXA2xx "Developer Manual" sections on the DMA controller and SSP Controllers
to determine the correct value. An SSP configured for byte-wide transfers would
-use a value of 8.
+use a value of 8. The driver will determine a reasonable default if
+dma_burst_size == 0.
The "pxa2xx_spi_chip.timeout" fields is used to efficiently handle
trailing bytes in the SSP receiver fifo. The correct value for this field is
@@ -137,7 +135,13 @@ function for asserting/deasserting a slave device chip select. If the field is
NULL, the pxa2xx_spi master controller driver assumes that the SSP port is
configured to use SSPFRM instead.
-NSSP SALVE SAMPLE
+NOTE: the SPI driver cannot control the chip select if SSPFRM is used, so the
+chipselect is dropped after each spi_transfer. Most devices need chip select
+asserted around the complete message. Use SSPFRM as a GPIO (through cs_control)
+to accommodate these chips.
+
+
+NSSP SLAVE SAMPLE
-----------------
The pxa2xx_spi_chip structure is passed to the pxa2xx_spi driver in the
"spi_board_info.controller_data" field. Below is a sample configuration using
@@ -206,18 +210,21 @@ static void __init streetracer_init(void)
DMA and PIO I/O Support
-----------------------
-The pxa2xx_spi driver support both DMA and interrupt driven PIO message
-transfers. The driver defaults to PIO mode and DMA transfers must enabled by
-setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and
-ensuring that the "pxa2xx_spi_chip.dma_burst_size" field is non-zero. The DMA
-mode support both coherent and stream based DMA mappings.
+The pxa2xx_spi driver supports both DMA and interrupt driven PIO message
+transfers. The driver defaults to PIO mode and DMA transfers must be enabled
+by setting the "enable_dma" flag in the "pxa2xx_spi_master" structure. The DMA
+mode supports both coherent and stream based DMA mappings.
The following logic is used to determine the type of I/O to be used on
a per "spi_transfer" basis:
-if !enable_dma or dma_burst_size == 0 then
+if !enable_dma then
always use PIO transfers
+if spi_message.len > 8191 then
+ print "rate limited" warning
+ use PIO transfers
+
if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then
use coherent DMA mode
diff --git a/Documentation/spi/spi-lm70llp b/Documentation/spi/spi-lm70llp
index 154bd02220b..463f6d01fa1 100644
--- a/Documentation/spi/spi-lm70llp
+++ b/Documentation/spi/spi-lm70llp
@@ -13,10 +13,20 @@ Description
This driver provides glue code connecting a National Semiconductor LM70 LLP
temperature sensor evaluation board to the kernel's SPI core subsystem.
+This is a SPI master controller driver. It can be used in conjunction with
+(layered under) the LM70 logical driver (a "SPI protocol driver").
In effect, this driver turns the parallel port interface on the eval board
into a SPI bus with a single device, which will be driven by the generic
LM70 driver (drivers/hwmon/lm70.c).
+
+Hardware Interfacing
+--------------------
+The schematic for this particular board (the LM70EVAL-LLP) is
+available (on page 4) here:
+
+ http://www.national.com/appinfo/tempsensors/files/LM70LLPEVALmanual.pdf
+
The hardware interfacing on the LM70 LLP eval board is as follows:
Parallel LM70 LLP
@@ -36,7 +46,7 @@ The hardware interfacing on the LM70 LLP eval board is as follows:
Note that since the LM70 uses a "3-wire" variant of SPI, the SI/SO pin
is connected to both pin D7 (as Master Out) and Select (as Master In)
-using an arrangment that lets either the parport or the LM70 pull the
+using an arrangement that lets either the parport or the LM70 pull the
pin low. This can't be shared with true SPI devices, but other 3-wire
devices might share the same SI/SO pin.
diff --git a/Documentation/spi/spi-sc18is602 b/Documentation/spi/spi-sc18is602
new file mode 100644
index 00000000000..a45702865a3
--- /dev/null
+++ b/Documentation/spi/spi-sc18is602
@@ -0,0 +1,36 @@
+Kernel driver spi-sc18is602
+===========================
+
+Supported chips:
+ * NXP SI18IS602/602B/603
+ Datasheet: http://www.nxp.com/documents/data_sheet/SC18IS602_602B_603.pdf
+
+Author:
+ Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+This driver provides connects a NXP SC18IS602/603 I2C-bus to SPI bridge to the
+kernel's SPI core subsystem.
+
+The driver does not probe for supported chips, since the SI18IS602/603 does not
+support Chip ID registers. You will have to instantiate the devices explicitly.
+Please see Documentation/i2c/instantiating-devices for details.
+
+
+Usage Notes
+-----------
+
+This driver requires the I2C adapter driver to support raw I2C messages. I2C
+adapter drivers which can only handle the SMBus protocol are not supported.
+
+The maximum SPI message size supported by SC18IS602/603 is 200 bytes. Attempts
+to initiate longer transfers will fail with -EINVAL. EEPROM read operations and
+similar large accesses have to be split into multiple chunks of no more than
+200 bytes per SPI message (128 bytes of data per message is recommended). This
+means that programs such as "cp" or "od", which automatically use large block
+sizes to access a device, can not be used directly to read data from EEPROM.
+Programs such as dd, where the block size can be specified, should be used
+instead.
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index 8861e47e5a2..7982bcc4d15 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -1,7 +1,7 @@
Overview of Linux kernel SPI support
====================================
-21-May-2007
+02-Feb-2012
What is SPI?
------------
@@ -34,7 +34,7 @@ SPI slave functions are usually not interoperable between vendors
- It may also be used to stream data in either direction (half duplex),
or both of them at the same time (full duplex).
- - Some devices may use eight bit words. Others may different word
+ - Some devices may use eight bit words. Others may use different word
lengths, such as streams of 12-bit or 20-bit digital samples.
- Words are usually sent with their most significant bit (MSB) first,
@@ -116,6 +116,13 @@ low order bit. So when a chip's timing diagram shows the clock
starting low (CPOL=0) and data stabilized for sampling during the
trailing clock edge (CPHA=1), that's SPI mode 1.
+Note that the clock mode is relevant as soon as the chipselect goes
+active. So the master must set the clock to inactive before selecting
+a slave, and the slave can tell the chosen polarity by sampling the
+clock level when its select line goes active. That's why many devices
+support for example both modes 0 and 3: they don't care about polarity,
+and always clock data in/out on rising clock edges.
+
How do these driver programming interfaces work?
------------------------------------------------
@@ -132,7 +139,7 @@ a command and then reading its response.
There are two types of SPI driver, here called:
- Controller drivers ... controllers may be built in to System-On-Chip
+ Controller drivers ... controllers may be built into System-On-Chip
processors, and often support both Master and Slave roles.
These drivers touch hardware registers and may use DMA.
Or they can be PIO bitbangers, needing just GPIO pins.
@@ -203,12 +210,12 @@ board should normally be set up and registered.
So for example arch/.../mach-*/board-*.c files might have code like:
- #include <asm/arch/spi.h> /* for mysoc_spi_data */
+ #include <mach/spi.h> /* for mysoc_spi_data */
/* if your mach-* infrastructure doesn't support kernels that can
* run on multiple boards, pdata wouldn't benefit from "__init".
*/
- static struct mysoc_spi_data __init pdata = { ... };
+ static struct mysoc_spi_data pdata __initdata = { ... };
static __init board_init(void)
{
@@ -220,7 +227,7 @@ So for example arch/.../mach-*/board-*.c files might have code like:
And SOC-specific utility code might look something like:
- #include <asm/arch/spi.h>
+ #include <mach/spi.h>
static struct platform_device spi2 = { ... };
@@ -338,17 +345,17 @@ SPI protocol drivers somewhat resemble platform device drivers:
},
.probe = CHIP_probe,
- .remove = __devexit_p(CHIP_remove),
+ .remove = CHIP_remove,
.suspend = CHIP_suspend,
.resume = CHIP_resume,
};
-The driver core will autmatically attempt to bind this driver to any SPI
+The driver core will automatically attempt to bind this driver to any SPI
device whose board_info gave a modalias of "CHIP". Your probe() code
might look like this unless you're creating a device which is managing
a bus (appearing under /sys/class/spi_master).
- static int __devinit CHIP_probe(struct spi_device *spi)
+ static int CHIP_probe(struct spi_device *spi)
{
struct CHIP *chip;
struct CHIP_platform_data *pdata;
@@ -379,8 +386,14 @@ any more such messages.
+ when bidirectional reads and writes start ... by how its
sequence of spi_transfer requests is arranged;
+ + which I/O buffers are used ... each spi_transfer wraps a
+ buffer for each transfer direction, supporting full duplex
+ (two pointers, maybe the same one in both cases) and half
+ duplex (one pointer is NULL) transfers;
+
+ optionally defining short delays after transfers ... using
- the spi_transfer.delay_usecs setting;
+ the spi_transfer.delay_usecs setting (this delay can be the
+ only protocol effect, if the buffer length is zero);
+ whether the chipselect becomes inactive after a transfer and
any delay ... by using the spi_transfer.cs_change flag;
@@ -470,9 +483,9 @@ also initialize its own internal state. (See below about bus numbering
and those methods.)
After you initialize the spi_master, then use spi_register_master() to
-publish it to the rest of the system. At that time, device nodes for
-the controller and any predeclared spi devices will be made available,
-and the driver model core will take care of binding them to drivers.
+publish it to the rest of the system. At that time, device nodes for the
+controller and any predeclared spi devices will be made available, and
+the driver model core will take care of binding them to drivers.
If you need to remove your SPI controller driver, spi_unregister_master()
will reverse the effect of spi_register_master().
@@ -498,28 +511,81 @@ SPI MASTER METHODS
This sets up the device clock rate, SPI mode, and word sizes.
Drivers may change the defaults provided by board_info, and then
call spi_setup(spi) to invoke this routine. It may sleep.
+
Unless each SPI slave has its own configuration registers, don't
change them right away ... otherwise drivers could corrupt I/O
that's in progress for other SPI devices.
- master->transfer(struct spi_device *spi, struct spi_message *message)
- This must not sleep. Its responsibility is arrange that the
- transfer happens and its complete() callback is issued. The two
- will normally happen later, after other transfers complete, and
- if the controller is idle it will need to be kickstarted.
+ ** BUG ALERT: for some reason the first version of
+ ** many spi_master drivers seems to get this wrong.
+ ** When you code setup(), ASSUME that the controller
+ ** is actively processing transfers for another device.
master->cleanup(struct spi_device *spi)
Your controller driver may use spi_device.controller_state to hold
state it dynamically associates with that device. If you do that,
be sure to provide the cleanup() method to free that state.
+ master->prepare_transfer_hardware(struct spi_master *master)
+ This will be called by the queue mechanism to signal to the driver
+ that a message is coming in soon, so the subsystem requests the
+ driver to prepare the transfer hardware by issuing this call.
+ This may sleep.
+
+ master->unprepare_transfer_hardware(struct spi_master *master)
+ This will be called by the queue mechanism to signal to the driver
+ that there are no more messages pending in the queue and it may
+ relax the hardware (e.g. by power management calls). This may sleep.
+
+ master->transfer_one_message(struct spi_master *master,
+ struct spi_message *mesg)
+ The subsystem calls the driver to transfer a single message while
+ queuing transfers that arrive in the meantime. When the driver is
+ finished with this message, it must call
+ spi_finalize_current_message() so the subsystem can issue the next
+ message. This may sleep.
+
+ master->transfer_one(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *transfer)
+ The subsystem calls the driver to transfer a single transfer while
+ queuing transfers that arrive in the meantime. When the driver is
+ finished with this transfer, it must call
+ spi_finalize_current_transfer() so the subsystem can issue the next
+ transfer. This may sleep. Note: transfer_one and transfer_one_message
+ are mutually exclusive; when both are set, the generic subsystem does
+ not call your transfer_one callback.
+
+ Return values:
+ negative errno: error
+ 0: transfer is finished
+ 1: transfer is still in progress
+
+ DEPRECATED METHODS
+
+ master->transfer(struct spi_device *spi, struct spi_message *message)
+ This must not sleep. Its responsibility is to arrange that the
+ transfer happens and its complete() callback is issued. The two
+ will normally happen later, after other transfers complete, and
+ if the controller is idle it will need to be kickstarted. This
+ method is not used on queued controllers and must be NULL if
+ transfer_one_message() and (un)prepare_transfer_hardware() are
+ implemented.
+
SPI MESSAGE QUEUE
-The bulk of the driver will be managing the I/O queue fed by transfer().
+If you are happy with the standard queueing mechanism provided by the
+SPI subsystem, just implement the queued methods specified above. Using
+the message queue has the upside of centralizing a lot of code and
+providing pure process-context execution of methods. The message queue
+can also be elevated to realtime priority on high-priority SPI traffic.
+
+Unless the queueing mechanism in the SPI subsystem is selected, the bulk
+of the driver will be managing the I/O queue fed by the now deprecated
+function transfer().
That queue could be purely conceptual. For example, a driver used only
-for low-frequency sensor acess might be fine using synchronous PIO.
+for low-frequency sensor access might be fine using synchronous PIO.
But the queue will probably be very real, using message->queue, PIO,
often DMA (especially if the root filesystem is in SPI flash), and
@@ -542,4 +608,6 @@ Stephen Street
Mark Underwood
Andrew Victor
Vitaly Wool
-
+Grant Likely
+Mark Brown
+Linus Walleij
diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev
index 5c8e1b988a0..3d14035b176 100644
--- a/Documentation/spi/spidev
+++ b/Documentation/spi/spidev
@@ -85,6 +85,12 @@ settings for data transfer parameters:
SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL
(clock polarity, idle high iff this is set) or SPI_CPHA (clock phase,
sample on trailing edge iff this is set) flags.
+ Note that this request is limited to SPI mode flags that fit in a
+ single byte.
+
+ SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t
+ which will return (RD) or assign (WR) the full SPI transfer mode,
+ not limited to the bits that fit in one byte.
SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte
which will return (RD) or assign (WR) the bit justification used to
@@ -126,8 +132,8 @@ NOTES:
FULL DUPLEX CHARACTER DEVICE API
================================
-See the sample program below for one example showing the use of the full
-duplex programming interface. (Although it doesn't perform a full duplex
+See the spidev_fdx.c sample program for one example showing the use of the
+full duplex programming interface. (Although it doesn't perform a full duplex
transfer.) The model is the same as that used in the kernel spi_sync()
request; the individual transfers offer the same capabilities as are
available to kernel drivers (except that it's not asynchronous).
@@ -141,167 +147,3 @@ and bitrate for each transfer segment.)
To make a full duplex request, provide both rx_buf and tx_buf for the
same transfer. It's even OK if those are the same buffer.
-
-
-SAMPLE PROGRAM
-==============
-
--------------------------------- CUT HERE
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <string.h>
-
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <linux/types.h>
-#include <linux/spi/spidev.h>
-
-
-static int verbose;
-
-static void do_read(int fd, int len)
-{
- unsigned char buf[32], *bp;
- int status;
-
- /* read at least 2 bytes, no more than 32 */
- if (len < 2)
- len = 2;
- else if (len > sizeof(buf))
- len = sizeof(buf);
- memset(buf, 0, sizeof buf);
-
- status = read(fd, buf, len);
- if (status < 0) {
- perror("read");
- return;
- }
- if (status != len) {
- fprintf(stderr, "short read\n");
- return;
- }
-
- printf("read(%2d, %2d): %02x %02x,", len, status,
- buf[0], buf[1]);
- status -= 2;
- bp = buf + 2;
- while (status-- > 0)
- printf(" %02x", *bp++);
- printf("\n");
-}
-
-static void do_msg(int fd, int len)
-{
- struct spi_ioc_transfer xfer[2];
- unsigned char buf[32], *bp;
- int status;
-
- memset(xfer, 0, sizeof xfer);
- memset(buf, 0, sizeof buf);
-
- if (len > sizeof buf)
- len = sizeof buf;
-
- buf[0] = 0xaa;
- xfer[0].tx_buf = (__u64) buf;
- xfer[0].len = 1;
-
- xfer[1].rx_buf = (__u64) buf;
- xfer[1].len = len;
-
- status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
- if (status < 0) {
- perror("SPI_IOC_MESSAGE");
- return;
- }
-
- printf("response(%2d, %2d): ", len, status);
- for (bp = buf; len; len--)
- printf(" %02x", *bp++);
- printf("\n");
-}
-
-static void dumpstat(const char *name, int fd)
-{
- __u8 mode, lsb, bits;
- __u32 speed;
-
- if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) {
- perror("SPI rd_mode");
- return;
- }
- if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
- perror("SPI rd_lsb_fist");
- return;
- }
- if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
- perror("SPI bits_per_word");
- return;
- }
- if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
- perror("SPI max_speed_hz");
- return;
- }
-
- printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",
- name, mode, bits, lsb ? "(lsb first) " : "", speed);
-}
-
-int main(int argc, char **argv)
-{
- int c;
- int readcount = 0;
- int msglen = 0;
- int fd;
- const char *name;
-
- while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
- switch (c) {
- case 'm':
- msglen = atoi(optarg);
- if (msglen < 0)
- goto usage;
- continue;
- case 'r':
- readcount = atoi(optarg);
- if (readcount < 0)
- goto usage;
- continue;
- case 'v':
- verbose++;
- continue;
- case 'h':
- case '?':
-usage:
- fprintf(stderr,
- "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
- argv[0]);
- return 1;
- }
- }
-
- if ((optind + 1) != argc)
- goto usage;
- name = argv[optind];
-
- fd = open(name, O_RDWR);
- if (fd < 0) {
- perror("open");
- return 1;
- }
-
- dumpstat(name, fd);
-
- if (msglen)
- do_msg(fd, msglen);
-
- if (readcount)
- do_read(fd, readcount);
-
- close(fd);
- return 0;
-}
diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c
new file mode 100644
index 00000000000..0ea3e51292f
--- /dev/null
+++ b/Documentation/spi/spidev_fdx.c
@@ -0,0 +1,158 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <linux/types.h>
+#include <linux/spi/spidev.h>
+
+
+static int verbose;
+
+static void do_read(int fd, int len)
+{
+ unsigned char buf[32], *bp;
+ int status;
+
+ /* read at least 2 bytes, no more than 32 */
+ if (len < 2)
+ len = 2;
+ else if (len > sizeof(buf))
+ len = sizeof(buf);
+ memset(buf, 0, sizeof buf);
+
+ status = read(fd, buf, len);
+ if (status < 0) {
+ perror("read");
+ return;
+ }
+ if (status != len) {
+ fprintf(stderr, "short read\n");
+ return;
+ }
+
+ printf("read(%2d, %2d): %02x %02x,", len, status,
+ buf[0], buf[1]);
+ status -= 2;
+ bp = buf + 2;
+ while (status-- > 0)
+ printf(" %02x", *bp++);
+ printf("\n");
+}
+
+static void do_msg(int fd, int len)
+{
+ struct spi_ioc_transfer xfer[2];
+ unsigned char buf[32], *bp;
+ int status;
+
+ memset(xfer, 0, sizeof xfer);
+ memset(buf, 0, sizeof buf);
+
+ if (len > sizeof buf)
+ len = sizeof buf;
+
+ buf[0] = 0xaa;
+ xfer[0].tx_buf = (unsigned long)buf;
+ xfer[0].len = 1;
+
+ xfer[1].rx_buf = (unsigned long) buf;
+ xfer[1].len = len;
+
+ status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
+ if (status < 0) {
+ perror("SPI_IOC_MESSAGE");
+ return;
+ }
+
+ printf("response(%2d, %2d): ", len, status);
+ for (bp = buf; len; len--)
+ printf(" %02x", *bp++);
+ printf("\n");
+}
+
+static void dumpstat(const char *name, int fd)
+{
+ __u8 lsb, bits;
+ __u32 mode, speed;
+
+ if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) {
+ perror("SPI rd_mode");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
+ perror("SPI rd_lsb_fist");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
+ perror("SPI bits_per_word");
+ return;
+ }
+ if (ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
+ perror("SPI max_speed_hz");
+ return;
+ }
+
+ printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n",
+ name, mode, bits, lsb ? "(lsb first) " : "", speed);
+}
+
+int main(int argc, char **argv)
+{
+ int c;
+ int readcount = 0;
+ int msglen = 0;
+ int fd;
+ const char *name;
+
+ while ((c = getopt(argc, argv, "hm:r:v")) != EOF) {
+ switch (c) {
+ case 'm':
+ msglen = atoi(optarg);
+ if (msglen < 0)
+ goto usage;
+ continue;
+ case 'r':
+ readcount = atoi(optarg);
+ if (readcount < 0)
+ goto usage;
+ continue;
+ case 'v':
+ verbose++;
+ continue;
+ case 'h':
+ case '?':
+usage:
+ fprintf(stderr,
+ "usage: %s [-h] [-m N] [-r N] /dev/spidevB.D\n",
+ argv[0]);
+ return 1;
+ }
+ }
+
+ if ((optind + 1) != argc)
+ goto usage;
+ name = argv[optind];
+
+ fd = open(name, O_RDWR);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ dumpstat(name, fd);
+
+ if (msglen)
+ do_msg(fd, msglen);
+
+ if (readcount)
+ do_read(fd, readcount);
+
+ close(fd);
+ return 0;
+}
diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c
index cf0e3ce0d52..3a2f9d59eda 100644
--- a/Documentation/spi/spidev_test.c
+++ b/Documentation/spi/spidev_test.c
@@ -30,7 +30,7 @@ static void pabort(const char *s)
}
static const char *device = "/dev/spidev1.1";
-static uint8_t mode;
+static uint32_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
@@ -57,8 +57,23 @@ static void transfer(int fd)
.bits_per_word = bits,
};
+ if (mode & SPI_TX_QUAD)
+ tr.tx_nbits = 4;
+ else if (mode & SPI_TX_DUAL)
+ tr.tx_nbits = 2;
+ if (mode & SPI_RX_QUAD)
+ tr.rx_nbits = 4;
+ else if (mode & SPI_RX_DUAL)
+ tr.rx_nbits = 2;
+ if (!(mode & SPI_LOOP)) {
+ if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
+ tr.rx_buf = 0;
+ else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
+ tr.tx_buf = 0;
+ }
+
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
- if (ret == 1)
+ if (ret < 1)
pabort("can't send spi message");
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
@@ -69,7 +84,7 @@ static void transfer(int fd)
puts("");
}
-void print_usage(const char *prog)
+static void print_usage(const char *prog)
{
printf("Usage: %s [-DsbdlHOLC3]\n", prog);
puts(" -D --device device to use (default /dev/spidev1.1)\n"
@@ -81,11 +96,15 @@ void print_usage(const char *prog)
" -O --cpol clock polarity\n"
" -L --lsb least significant bit first\n"
" -C --cs-high chip select active high\n"
- " -3 --3wire SI/SO signals shared\n");
+ " -3 --3wire SI/SO signals shared\n"
+ " -N --no-cs no chip select\n"
+ " -R --ready slave pulls low to pause\n"
+ " -2 --dual dual transfer\n"
+ " -4 --quad quad transfer\n");
exit(1);
}
-void parse_opts(int argc, char *argv[])
+static void parse_opts(int argc, char *argv[])
{
while (1) {
static const struct option lopts[] = {
@@ -99,11 +118,15 @@ void parse_opts(int argc, char *argv[])
{ "lsb", 0, 0, 'L' },
{ "cs-high", 0, 0, 'C' },
{ "3wire", 0, 0, '3' },
+ { "no-cs", 0, 0, 'N' },
+ { "ready", 0, 0, 'R' },
+ { "dual", 0, 0, '2' },
+ { "quad", 0, 0, '4' },
{ NULL, 0, 0, 0 },
};
int c;
- c = getopt_long(argc, argv, "D:s:d:b:lHOLC3", lopts, NULL);
+ c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL);
if (c == -1)
break;
@@ -139,11 +162,29 @@ void parse_opts(int argc, char *argv[])
case '3':
mode |= SPI_3WIRE;
break;
+ case 'N':
+ mode |= SPI_NO_CS;
+ break;
+ case 'R':
+ mode |= SPI_READY;
+ break;
+ case '2':
+ mode |= SPI_TX_DUAL;
+ break;
+ case '4':
+ mode |= SPI_TX_QUAD;
+ break;
default:
print_usage(argv[0]);
break;
}
}
+ if (mode & SPI_LOOP) {
+ if (mode & SPI_TX_DUAL)
+ mode |= SPI_RX_DUAL;
+ if (mode & SPI_TX_QUAD)
+ mode |= SPI_RX_QUAD;
+ }
}
int main(int argc, char *argv[])
@@ -160,11 +201,11 @@ int main(int argc, char *argv[])
/*
* spi mode
*/
- ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
pabort("can't set spi mode");
- ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
+ ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
pabort("can't get spi mode");
@@ -190,7 +231,7 @@ int main(int argc, char *argv[])
if (ret == -1)
pabort("can't get max speed hz");
- printf("spi mode: %d\n", mode);
+ printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);