diff options
Diffstat (limited to 'Documentation/spi')
| -rw-r--r-- | Documentation/spi/00-INDEX | 22 | ||||
| -rw-r--r-- | Documentation/spi/ep93xx_spi | 12 | ||||
| -rw-r--r-- | Documentation/spi/pxa2xx | 15 | ||||
| -rw-r--r-- | Documentation/spi/spi-lm70llp | 2 | ||||
| -rw-r--r-- | Documentation/spi/spi-sc18is602 | 36 | ||||
| -rw-r--r-- | Documentation/spi/spi-summary | 85 | ||||
| -rw-r--r-- | Documentation/spi/spidev | 6 | ||||
| -rw-r--r-- | Documentation/spi/spidev_fdx.c | 8 | ||||
| -rw-r--r-- | Documentation/spi/spidev_test.c | 45 |
9 files changed, 191 insertions, 40 deletions
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/ep93xx_spi b/Documentation/spi/ep93xx_spi index 6325f5b4863..832ddce6e5f 100644 --- a/Documentation/spi/ep93xx_spi +++ b/Documentation/spi/ep93xx_spi @@ -26,7 +26,7 @@ arch/arm/mach-ep93xx/ts72xx.c: #include <linux/gpio.h> #include <linux/spi/spi.h> -#include <mach/ep93xx_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 @@ -88,6 +88,16 @@ static void __init ts72xx_init_machine(void) 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 diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx index 6bb916d57c9..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 arch/arm/mach-pxa/include/mach/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,11 +85,11 @@ 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 -"arch/arm/mach-pxa/include/mach/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. All fields are optional. @@ -143,7 +138,7 @@ configured to use SSPFRM instead. 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 accomodate these chips. +to accommodate these chips. NSSP SLAVE SAMPLE diff --git a/Documentation/spi/spi-lm70llp b/Documentation/spi/spi-lm70llp index 34a9cfd746b..463f6d01fa1 100644 --- a/Documentation/spi/spi-lm70llp +++ b/Documentation/spi/spi-lm70llp @@ -46,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 4884cb33845..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, @@ -121,7 +121,7 @@ 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 alway clock data in/out on rising clock edges. +and always clock data in/out on rising clock edges. How do these driver programming interfaces work? @@ -139,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. @@ -215,7 +215,7 @@ So for example arch/.../mach-*/board-*.c files might have code like: /* 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 __initdata pdata = { ... }; + static struct mysoc_spi_data pdata __initdata = { ... }; static __init board_init(void) { @@ -345,7 +345,7 @@ 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, }; @@ -355,7 +355,7 @@ 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; @@ -483,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(). @@ -521,21 +521,68 @@ SPI MASTER METHODS ** When you code setup(), ASSUME that the controller ** is actively processing transfers for another device. - 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. - 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 access might be fine using synchronous PIO. @@ -561,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 ed2da5e5b28..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 diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c index 36ec0774ca0..0ea3e51292f 100644 --- a/Documentation/spi/spidev_fdx.c +++ b/Documentation/spi/spidev_fdx.c @@ -78,10 +78,10 @@ static void do_msg(int fd, int len) static void dumpstat(const char *name, int fd) { - __u8 mode, lsb, bits; - __u32 speed; + __u8 lsb, bits; + __u32 mode, speed; - if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { + if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) { perror("SPI rd_mode"); return; } @@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd) return; } - printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n", + printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n", name, mode, bits, lsb ? "(lsb first) " : "", speed); } diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 16feda90146..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,6 +57,21 @@ 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) pabort("can't send spi message"); @@ -81,7 +96,11 @@ static 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); } @@ -101,11 +120,13 @@ static void parse_opts(int argc, char *argv[]) { "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:lHOLC3NR", lopts, NULL); + c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL); if (c == -1) break; @@ -147,11 +168,23 @@ static void parse_opts(int argc, char *argv[]) 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[]) @@ -168,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"); @@ -198,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); |
