mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-21 16:29:59 +00:00
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/spi-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/spi-2.6: [PATCH] SPI: spi_bitbang: clocking fixes [PATCH] spi: Update to PXA2xx SPI Driver [PATCH] SPI: busnum == 0 needs to work [PATCH] SPI: devices can require LSB-first encodings [PATCH] SPI: Renamed bitbang_transfer_setup to spi_bitbang_setup_transfer and export it [PATCH] SPI: Add David as the SPI subsystem maintainer [PATCH] SPI: spi bounce buffer has a minimum length [PATCH] SPI: spi whitespace fixes [PATCH] SPI: add PXA2xx SSP SPI Driver [PATCH] SPI: per-transfer overrides for wordsize and clocking
This commit is contained in:
commit
0c056c50a6
11 changed files with 1941 additions and 41 deletions
234
Documentation/spi/pxa2xx
Normal file
234
Documentation/spi/pxa2xx
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
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
|
||||||
|
|
||||||
|
- Support for any PXA2xx SSP
|
||||||
|
- SSP PIO and SSP DMA data transfers.
|
||||||
|
- External and Internal (SSPFRM) chip selects.
|
||||||
|
- Per slave device (chip) configuration.
|
||||||
|
- Full suspend, freeze, resume support.
|
||||||
|
|
||||||
|
The driver is built around a "spi_message" fifo serviced by workqueue and a
|
||||||
|
tasklet. The workqueue, "pump_messages", drives message fifo and the tasklet
|
||||||
|
(pump_transfer) is responsible for queuing SPI transactions and setting up and
|
||||||
|
launching the dma/interrupt driven transfers.
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
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".
|
||||||
|
|
||||||
|
The "pxa2xx_spi_master.num_chipselect" field is used to determine the number of
|
||||||
|
slave device (chips) attached to this SPI master.
|
||||||
|
|
||||||
|
The "pxa2xx_spi_master.enable_dma" field informs the driver that SSP DMA should
|
||||||
|
be used. This caused the driver to acquire two DMA channels: rx_channel and
|
||||||
|
tx_channel. The rx_channel has a higher DMA service priority the tx_channel.
|
||||||
|
See the "PXA2xx Developer Manual" section "DMA Controller".
|
||||||
|
|
||||||
|
NSSP MASTER SAMPLE
|
||||||
|
------------------
|
||||||
|
Below is a sample configuration using the PXA255 NSSP.
|
||||||
|
|
||||||
|
static struct resource pxa_spi_nssp_resources[] = {
|
||||||
|
[0] = {
|
||||||
|
.start = __PREG(SSCR0_P(2)), /* Start address of NSSP */
|
||||||
|
.end = __PREG(SSCR0_P(2)) + 0x2c, /* Range of registers */
|
||||||
|
.flags = IORESOURCE_MEM,
|
||||||
|
},
|
||||||
|
[1] = {
|
||||||
|
.start = IRQ_NSSP, /* NSSP IRQ */
|
||||||
|
.end = IRQ_NSSP,
|
||||||
|
.flags = IORESOURCE_IRQ,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pxa2xx_spi_master pxa_nssp_master_info = {
|
||||||
|
.ssp_type = PXA25x_NSSP, /* Type of SSP */
|
||||||
|
.clock_enable = CKEN9_NSSP, /* NSSP Peripheral clock */
|
||||||
|
.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
|
||||||
|
.enable_dma = 1, /* Enables NSSP DMA */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device pxa_spi_nssp = {
|
||||||
|
.name = "pxa2xx-spi", /* MUST BE THIS VALUE, so device match driver */
|
||||||
|
.id = 2, /* Bus number, MUST MATCH SSP number 1..n */
|
||||||
|
.resource = pxa_spi_nssp_resources,
|
||||||
|
.num_resources = ARRAY_SIZE(pxa_spi_nssp_resources),
|
||||||
|
.dev = {
|
||||||
|
.platform_data = &pxa_nssp_master_info, /* Passed to driver */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_device *devices[] __initdata = {
|
||||||
|
&pxa_spi_nssp,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __init board_init(void)
|
||||||
|
{
|
||||||
|
(void)platform_add_device(devices, ARRAY_SIZE(devices));
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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
|
||||||
|
will uses the configuration whenever the driver communicates with the slave
|
||||||
|
device.
|
||||||
|
|
||||||
|
struct pxa2xx_spi_chip {
|
||||||
|
u8 tx_threshold;
|
||||||
|
u8 rx_threshold;
|
||||||
|
u8 dma_burst_size;
|
||||||
|
u32 timeout_microsecs;
|
||||||
|
u8 enable_loopback;
|
||||||
|
void (*cs_control)(u32 command);
|
||||||
|
};
|
||||||
|
|
||||||
|
The "pxa2xx_spi_chip.tx_threshold" and "pxa2xx_spi_chip.rx_threshold" fields are
|
||||||
|
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,
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
The "pxa2xx_spi_chip.timeout_microsecs" fields is used to efficiently handle
|
||||||
|
trailing bytes in the SSP receiver fifo. The correct value for this field is
|
||||||
|
dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
|
||||||
|
slave device. Please note the the PXA2xx SSP 1 does not support trailing byte
|
||||||
|
timeouts and must busy-wait any trailing bytes.
|
||||||
|
|
||||||
|
The "pxa2xx_spi_chip.enable_loopback" field is used to place the SSP porting
|
||||||
|
into internal loopback mode. In this mode the SSP controller internally
|
||||||
|
connects the SSPTX pin the the SSPRX pin. This is useful for initial setup
|
||||||
|
testing.
|
||||||
|
|
||||||
|
The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
|
||||||
|
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
|
||||||
|
-----------------
|
||||||
|
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
|
||||||
|
the PXA255 NSSP.
|
||||||
|
|
||||||
|
/* Chip Select control for the CS8415A SPI slave device */
|
||||||
|
static void cs8415a_cs_control(u32 command)
|
||||||
|
{
|
||||||
|
if (command & PXA2XX_CS_ASSERT)
|
||||||
|
GPCR(2) = GPIO_bit(2);
|
||||||
|
else
|
||||||
|
GPSR(2) = GPIO_bit(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Chip Select control for the CS8405A SPI slave device */
|
||||||
|
static void cs8405a_cs_control(u32 command)
|
||||||
|
{
|
||||||
|
if (command & PXA2XX_CS_ASSERT)
|
||||||
|
GPCR(3) = GPIO_bit(3);
|
||||||
|
else
|
||||||
|
GPSR(3) = GPIO_bit(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pxa2xx_spi_chip cs8415a_chip_info = {
|
||||||
|
.tx_threshold = 12, /* SSP hardward FIFO threshold */
|
||||||
|
.rx_threshold = 4, /* SSP hardward FIFO threshold */
|
||||||
|
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
||||||
|
.timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
|
||||||
|
.cs_control = cs8415a_cs_control, /* Use external chip select */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct pxa2xx_spi_chip cs8405a_chip_info = {
|
||||||
|
.tx_threshold = 12, /* SSP hardward FIFO threshold */
|
||||||
|
.rx_threshold = 4, /* SSP hardward FIFO threshold */
|
||||||
|
.dma_burst_size = 8, /* Byte wide transfers used so 8 byte bursts */
|
||||||
|
.timeout_microsecs = 64, /* Wait at least 64usec to handle trailing */
|
||||||
|
.cs_control = cs8405a_cs_control, /* Use external chip select */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct spi_board_info streetracer_spi_board_info[] __initdata = {
|
||||||
|
{
|
||||||
|
.modalias = "cs8415a", /* Name of spi_driver for this device */
|
||||||
|
.max_speed_hz = 3686400, /* Run SSP as fast a possbile */
|
||||||
|
.bus_num = 2, /* Framework bus number */
|
||||||
|
.chip_select = 0, /* Framework chip select */
|
||||||
|
.platform_data = NULL; /* No spi_driver specific config */
|
||||||
|
.controller_data = &cs8415a_chip_info, /* Master chip config */
|
||||||
|
.irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.modalias = "cs8405a", /* Name of spi_driver for this device */
|
||||||
|
.max_speed_hz = 3686400, /* Run SSP as fast a possbile */
|
||||||
|
.bus_num = 2, /* Framework bus number */
|
||||||
|
.chip_select = 1, /* Framework chip select */
|
||||||
|
.controller_data = &cs8405a_chip_info, /* Master chip config */
|
||||||
|
.irq = STREETRACER_APCI_IRQ, /* Slave device interrupt */
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void __init streetracer_init(void)
|
||||||
|
{
|
||||||
|
spi_register_board_info(streetracer_spi_board_info,
|
||||||
|
ARRAY_SIZE(streetracer_spi_board_info));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 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 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
|
||||||
|
always use PIO transfers
|
||||||
|
|
||||||
|
if spi_message.is_dma_mapped and rx_dma_buf != 0 and tx_dma_buf != 0 then
|
||||||
|
use coherent DMA mode
|
||||||
|
|
||||||
|
if rx_buf and tx_buf are aligned on 8 byte boundary then
|
||||||
|
use streaming DMA mode
|
||||||
|
|
||||||
|
otherwise
|
||||||
|
use PIO transfer
|
||||||
|
|
||||||
|
THANKS TO
|
||||||
|
---------
|
||||||
|
|
||||||
|
David Brownell and others for mentoring the development of this driver.
|
||||||
|
|
|
@ -414,7 +414,33 @@ to get the driver-private data allocated for that device.
|
||||||
The driver will initialize the fields of that spi_master, including the
|
The driver will initialize the fields of that spi_master, including the
|
||||||
bus number (maybe the same as the platform device ID) and three methods
|
bus number (maybe the same as the platform device ID) and three methods
|
||||||
used to interact with the SPI core and SPI protocol drivers. It will
|
used to interact with the SPI core and SPI protocol drivers. It will
|
||||||
also initialize its own internal state.
|
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.
|
||||||
|
|
||||||
|
If you need to remove your SPI controller driver, spi_unregister_master()
|
||||||
|
will reverse the effect of spi_register_master().
|
||||||
|
|
||||||
|
|
||||||
|
BUS NUMBERING
|
||||||
|
|
||||||
|
Bus numbering is important, since that's how Linux identifies a given
|
||||||
|
SPI bus (shared SCK, MOSI, MISO). Valid bus numbers start at zero. On
|
||||||
|
SOC systems, the bus numbers should match the numbers defined by the chip
|
||||||
|
manufacturer. For example, hardware controller SPI2 would be bus number 2,
|
||||||
|
and spi_board_info for devices connected to it would use that number.
|
||||||
|
|
||||||
|
If you don't have such hardware-assigned bus number, and for some reason
|
||||||
|
you can't just assign them, then provide a negative bus number. That will
|
||||||
|
then be replaced by a dynamically assigned number. You'd then need to treat
|
||||||
|
this as a non-static configuration (see above).
|
||||||
|
|
||||||
|
|
||||||
|
SPI MASTER METHODS
|
||||||
|
|
||||||
master->setup(struct spi_device *spi)
|
master->setup(struct spi_device *spi)
|
||||||
This sets up the device clock rate, SPI mode, and word sizes.
|
This sets up the device clock rate, SPI mode, and word sizes.
|
||||||
|
@ -431,6 +457,9 @@ also initialize its own internal state.
|
||||||
state it dynamically associates with that device. If you do that,
|
state it dynamically associates with that device. If you do that,
|
||||||
be sure to provide the cleanup() method to free that state.
|
be sure to provide the cleanup() method to free that state.
|
||||||
|
|
||||||
|
|
||||||
|
SPI MESSAGE QUEUE
|
||||||
|
|
||||||
The bulk of the driver will be managing the I/O queue fed by transfer().
|
The bulk of the driver will be managing the I/O queue fed by transfer().
|
||||||
|
|
||||||
That queue could be purely conceptual. For example, a driver used only
|
That queue could be purely conceptual. For example, a driver used only
|
||||||
|
@ -440,6 +469,9 @@ But the queue will probably be very real, using message->queue, PIO,
|
||||||
often DMA (especially if the root filesystem is in SPI flash), and
|
often DMA (especially if the root filesystem is in SPI flash), and
|
||||||
execution contexts like IRQ handlers, tasklets, or workqueues (such
|
execution contexts like IRQ handlers, tasklets, or workqueues (such
|
||||||
as keventd). Your driver can be as fancy, or as simple, as you need.
|
as keventd). Your driver can be as fancy, or as simple, as you need.
|
||||||
|
Such a transfer() method would normally just add the message to a
|
||||||
|
queue, and then start some asynchronous transfer engine (unless it's
|
||||||
|
already running).
|
||||||
|
|
||||||
|
|
||||||
THANKS TO
|
THANKS TO
|
||||||
|
|
|
@ -2518,6 +2518,12 @@ M: perex@suse.cz
|
||||||
L: alsa-devel@alsa-project.org
|
L: alsa-devel@alsa-project.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
|
|
||||||
|
SPI SUBSYSTEM
|
||||||
|
P: David Brownell
|
||||||
|
M: dbrownell@users.sourceforge.net
|
||||||
|
L: spi-devel-general@lists.sourceforge.net
|
||||||
|
S: Maintained
|
||||||
|
|
||||||
TPM DEVICE DRIVER
|
TPM DEVICE DRIVER
|
||||||
P: Kylene Hall
|
P: Kylene Hall
|
||||||
M: kjhall@us.ibm.com
|
M: kjhall@us.ibm.com
|
||||||
|
|
|
@ -75,6 +75,14 @@ config SPI_BUTTERFLY
|
||||||
inexpensive battery powered microcontroller evaluation board.
|
inexpensive battery powered microcontroller evaluation board.
|
||||||
This same cable can be used to flash new firmware.
|
This same cable can be used to flash new firmware.
|
||||||
|
|
||||||
|
config SPI_PXA2XX
|
||||||
|
tristate "PXA2xx SSP SPI master"
|
||||||
|
depends on SPI_MASTER && ARCH_PXA && EXPERIMENTAL
|
||||||
|
help
|
||||||
|
This enables using a PXA2xx SSP port as a SPI master controller.
|
||||||
|
The driver can be configured to use any SSP port and additional
|
||||||
|
documentation can be found a Documentation/spi/pxa2xx.
|
||||||
|
|
||||||
#
|
#
|
||||||
# Add new SPI master controllers in alphabetical order above this line
|
# Add new SPI master controllers in alphabetical order above this line
|
||||||
#
|
#
|
||||||
|
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_SPI_MASTER) += spi.o
|
||||||
# SPI master controller drivers (bus)
|
# SPI master controller drivers (bus)
|
||||||
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
|
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
|
||||||
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
|
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
|
||||||
|
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
|
||||||
# ... add above this line ...
|
# ... add above this line ...
|
||||||
|
|
||||||
# SPI protocol drivers (device/link on bus)
|
# SPI protocol drivers (device/link on bus)
|
||||||
|
|
1467
drivers/spi/pxa2xx_spi.c
Normal file
1467
drivers/spi/pxa2xx_spi.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -395,7 +395,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master);
|
||||||
int __init_or_module
|
int __init_or_module
|
||||||
spi_register_master(struct spi_master *master)
|
spi_register_master(struct spi_master *master)
|
||||||
{
|
{
|
||||||
static atomic_t dyn_bus_id = ATOMIC_INIT(0);
|
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1);
|
||||||
struct device *dev = master->cdev.dev;
|
struct device *dev = master->cdev.dev;
|
||||||
int status = -ENODEV;
|
int status = -ENODEV;
|
||||||
int dynamic = 0;
|
int dynamic = 0;
|
||||||
|
@ -404,7 +404,7 @@ spi_register_master(struct spi_master *master)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
/* 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 = 1;
|
dynamic = 1;
|
||||||
}
|
}
|
||||||
|
@ -522,7 +522,8 @@ int spi_sync(struct spi_device *spi, struct spi_message *message)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_sync);
|
EXPORT_SYMBOL_GPL(spi_sync);
|
||||||
|
|
||||||
#define SPI_BUFSIZ (SMP_CACHE_BYTES)
|
/* portable code must never pass more than 32 bytes */
|
||||||
|
#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES)
|
||||||
|
|
||||||
static u8 *buf;
|
static u8 *buf;
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,45 @@ static unsigned bitbang_txrx_32(
|
||||||
return t->len - count;
|
return t->len - count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
|
||||||
|
{
|
||||||
|
struct spi_bitbang_cs *cs = spi->controller_state;
|
||||||
|
u8 bits_per_word;
|
||||||
|
u32 hz;
|
||||||
|
|
||||||
|
if (t) {
|
||||||
|
bits_per_word = t->bits_per_word;
|
||||||
|
hz = t->speed_hz;
|
||||||
|
} else {
|
||||||
|
bits_per_word = 0;
|
||||||
|
hz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* spi_transfer level calls that work per-word */
|
||||||
|
if (!bits_per_word)
|
||||||
|
bits_per_word = spi->bits_per_word;
|
||||||
|
if (bits_per_word <= 8)
|
||||||
|
cs->txrx_bufs = bitbang_txrx_8;
|
||||||
|
else if (bits_per_word <= 16)
|
||||||
|
cs->txrx_bufs = bitbang_txrx_16;
|
||||||
|
else if (bits_per_word <= 32)
|
||||||
|
cs->txrx_bufs = bitbang_txrx_32;
|
||||||
|
else
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* nsecs = (clock period)/2 */
|
||||||
|
if (!hz)
|
||||||
|
hz = spi->max_speed_hz;
|
||||||
|
if (hz) {
|
||||||
|
cs->nsecs = (1000000000/2) / hz;
|
||||||
|
if (cs->nsecs > (MAX_UDELAY_MS * 1000 * 1000))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_bitbang_setup - default setup for per-word I/O loops
|
* spi_bitbang_setup - default setup for per-word I/O loops
|
||||||
*/
|
*/
|
||||||
|
@ -145,8 +184,16 @@ int spi_bitbang_setup(struct spi_device *spi)
|
||||||
{
|
{
|
||||||
struct spi_bitbang_cs *cs = spi->controller_state;
|
struct spi_bitbang_cs *cs = spi->controller_state;
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
|
int retval;
|
||||||
|
|
||||||
if (!spi->max_speed_hz)
|
bitbang = spi_master_get_devdata(spi->master);
|
||||||
|
|
||||||
|
/* REVISIT: some systems will want to support devices using lsb-first
|
||||||
|
* bit encodings on the wire. In pure software that would be trivial,
|
||||||
|
* just bitbang_txrx_le_cphaX() routines shifting the other way, and
|
||||||
|
* some hardware controllers also have this support.
|
||||||
|
*/
|
||||||
|
if ((spi->mode & SPI_LSB_FIRST) != 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!cs) {
|
if (!cs) {
|
||||||
|
@ -155,32 +202,20 @@ int spi_bitbang_setup(struct spi_device *spi)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
spi->controller_state = cs;
|
spi->controller_state = cs;
|
||||||
}
|
}
|
||||||
bitbang = spi_master_get_devdata(spi->master);
|
|
||||||
|
|
||||||
if (!spi->bits_per_word)
|
if (!spi->bits_per_word)
|
||||||
spi->bits_per_word = 8;
|
spi->bits_per_word = 8;
|
||||||
|
|
||||||
/* spi_transfer level calls that work per-word */
|
|
||||||
if (spi->bits_per_word <= 8)
|
|
||||||
cs->txrx_bufs = bitbang_txrx_8;
|
|
||||||
else if (spi->bits_per_word <= 16)
|
|
||||||
cs->txrx_bufs = bitbang_txrx_16;
|
|
||||||
else if (spi->bits_per_word <= 32)
|
|
||||||
cs->txrx_bufs = bitbang_txrx_32;
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* per-word shift register access, in hardware or bitbanging */
|
/* per-word shift register access, in hardware or bitbanging */
|
||||||
cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
|
cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)];
|
||||||
if (!cs->txrx_word)
|
if (!cs->txrx_word)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
/* nsecs = (clock period)/2 */
|
retval = spi_bitbang_setup_transfer(spi, NULL);
|
||||||
cs->nsecs = (1000000000/2) / (spi->max_speed_hz);
|
if (retval < 0)
|
||||||
if (cs->nsecs > MAX_UDELAY_MS * 1000)
|
return retval;
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n",
|
dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec/bit\n",
|
||||||
__FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
|
__FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA),
|
||||||
spi->bits_per_word, 2 * cs->nsecs);
|
spi->bits_per_word, 2 * cs->nsecs);
|
||||||
|
|
||||||
|
@ -246,6 +281,8 @@ static void bitbang_work(void *_bitbang)
|
||||||
unsigned tmp;
|
unsigned tmp;
|
||||||
unsigned cs_change;
|
unsigned cs_change;
|
||||||
int status;
|
int status;
|
||||||
|
int (*setup_transfer)(struct spi_device *,
|
||||||
|
struct spi_transfer *);
|
||||||
|
|
||||||
m = container_of(bitbang->queue.next, struct spi_message,
|
m = container_of(bitbang->queue.next, struct spi_message,
|
||||||
queue);
|
queue);
|
||||||
|
@ -262,6 +299,7 @@ static void bitbang_work(void *_bitbang)
|
||||||
tmp = 0;
|
tmp = 0;
|
||||||
cs_change = 1;
|
cs_change = 1;
|
||||||
status = 0;
|
status = 0;
|
||||||
|
setup_transfer = NULL;
|
||||||
|
|
||||||
list_for_each_entry (t, &m->transfers, transfer_list) {
|
list_for_each_entry (t, &m->transfers, transfer_list) {
|
||||||
if (bitbang->shutdown) {
|
if (bitbang->shutdown) {
|
||||||
|
@ -269,6 +307,20 @@ static void bitbang_work(void *_bitbang)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* override or restore speed and wordsize */
|
||||||
|
if (t->speed_hz || t->bits_per_word) {
|
||||||
|
setup_transfer = bitbang->setup_transfer;
|
||||||
|
if (!setup_transfer) {
|
||||||
|
status = -ENOPROTOOPT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (setup_transfer) {
|
||||||
|
status = setup_transfer(spi, t);
|
||||||
|
if (status < 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* set up default clock polarity, and activate chip;
|
/* set up default clock polarity, and activate chip;
|
||||||
* this implicitly updates clock and spi modes as
|
* this implicitly updates clock and spi modes as
|
||||||
* previously recorded for this device via setup().
|
* previously recorded for this device via setup().
|
||||||
|
@ -325,6 +377,10 @@ static void bitbang_work(void *_bitbang)
|
||||||
m->status = status;
|
m->status = status;
|
||||||
m->complete(m->context);
|
m->complete(m->context);
|
||||||
|
|
||||||
|
/* restore speed and wordsize */
|
||||||
|
if (setup_transfer)
|
||||||
|
setup_transfer(spi, NULL);
|
||||||
|
|
||||||
/* normally deactivate chipselect ... unless no error and
|
/* normally deactivate chipselect ... unless no error and
|
||||||
* cs_change has hinted that the next message will probably
|
* cs_change has hinted that the next message will probably
|
||||||
* be for this chip too.
|
* be for this chip too.
|
||||||
|
@ -348,6 +404,7 @@ int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
|
||||||
{
|
{
|
||||||
struct spi_bitbang *bitbang;
|
struct spi_bitbang *bitbang;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
m->actual_length = 0;
|
m->actual_length = 0;
|
||||||
m->status = -EINPROGRESS;
|
m->status = -EINPROGRESS;
|
||||||
|
@ -357,11 +414,15 @@ int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
|
||||||
return -ESHUTDOWN;
|
return -ESHUTDOWN;
|
||||||
|
|
||||||
spin_lock_irqsave(&bitbang->lock, flags);
|
spin_lock_irqsave(&bitbang->lock, flags);
|
||||||
|
if (!spi->max_speed_hz)
|
||||||
|
status = -ENETDOWN;
|
||||||
|
else {
|
||||||
list_add_tail(&m->queue, &bitbang->queue);
|
list_add_tail(&m->queue, &bitbang->queue);
|
||||||
queue_work(bitbang->workqueue, &bitbang->work);
|
queue_work(bitbang->workqueue, &bitbang->work);
|
||||||
|
}
|
||||||
spin_unlock_irqrestore(&bitbang->lock, flags);
|
spin_unlock_irqrestore(&bitbang->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return status;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
|
EXPORT_SYMBOL_GPL(spi_bitbang_transfer);
|
||||||
|
|
||||||
|
@ -406,6 +467,9 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
|
||||||
bitbang->use_dma = 0;
|
bitbang->use_dma = 0;
|
||||||
bitbang->txrx_bufs = spi_bitbang_bufs;
|
bitbang->txrx_bufs = spi_bitbang_bufs;
|
||||||
if (!bitbang->master->setup) {
|
if (!bitbang->master->setup) {
|
||||||
|
if (!bitbang->setup_transfer)
|
||||||
|
bitbang->setup_transfer =
|
||||||
|
spi_bitbang_setup_transfer;
|
||||||
bitbang->master->setup = spi_bitbang_setup;
|
bitbang->master->setup = spi_bitbang_setup;
|
||||||
bitbang->master->cleanup = spi_bitbang_cleanup;
|
bitbang->master->cleanup = spi_bitbang_cleanup;
|
||||||
}
|
}
|
||||||
|
|
68
include/asm-arm/arch-pxa/pxa2xx_spi.h
Normal file
68
include/asm-arm/arch-pxa/pxa2xx_spi.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PXA2XX_SPI_H_
|
||||||
|
#define PXA2XX_SPI_H_
|
||||||
|
|
||||||
|
#define PXA2XX_CS_ASSERT (0x01)
|
||||||
|
#define PXA2XX_CS_DEASSERT (0x02)
|
||||||
|
|
||||||
|
#if defined(CONFIG_PXA25x)
|
||||||
|
#define CLOCK_SPEED_HZ 3686400
|
||||||
|
#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/2/(x+1))<<8)&0x0000ff00)
|
||||||
|
#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
|
||||||
|
#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
|
||||||
|
#elif defined(CONFIG_PXA27x)
|
||||||
|
#define CLOCK_SPEED_HZ 13000000
|
||||||
|
#define SSP1_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
|
||||||
|
#define SSP2_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
|
||||||
|
#define SSP3_SerClkDiv(x) (((CLOCK_SPEED_HZ/(x+1))<<8)&0x000fff00)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SSP1_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(1)))))
|
||||||
|
#define SSP2_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(2)))))
|
||||||
|
#define SSP3_VIRT ((void *)(io_p2v(__PREG(SSCR0_P(3)))))
|
||||||
|
|
||||||
|
enum pxa_ssp_type {
|
||||||
|
SSP_UNDEFINED = 0,
|
||||||
|
PXA25x_SSP, /* pxa 210, 250, 255, 26x */
|
||||||
|
PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
|
||||||
|
PXA27x_SSP,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* device.platform_data for SSP controller devices */
|
||||||
|
struct pxa2xx_spi_master {
|
||||||
|
enum pxa_ssp_type ssp_type;
|
||||||
|
u32 clock_enable;
|
||||||
|
u16 num_chipselect;
|
||||||
|
u8 enable_dma;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* spi_board_info.controller_data for SPI slave devices,
|
||||||
|
* copied to spi_device.platform_data ... mostly for dma tuning
|
||||||
|
*/
|
||||||
|
struct pxa2xx_spi_chip {
|
||||||
|
u8 tx_threshold;
|
||||||
|
u8 rx_threshold;
|
||||||
|
u8 dma_burst_size;
|
||||||
|
u32 timeout_microsecs;
|
||||||
|
u8 enable_loopback;
|
||||||
|
void (*cs_control)(u32 command);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /*PXA2XX_SPI_H_*/
|
|
@ -31,13 +31,18 @@ extern struct bus_type spi_bus_type;
|
||||||
* @master: SPI controller used with the device.
|
* @master: SPI controller used with the device.
|
||||||
* @max_speed_hz: Maximum clock rate to be used with this chip
|
* @max_speed_hz: Maximum clock rate to be used with this chip
|
||||||
* (on this board); may be changed by the device's driver.
|
* (on this board); may be changed by the device's driver.
|
||||||
|
* The spi_transfer.speed_hz can override this for each transfer.
|
||||||
* @chip-select: Chipselect, distinguishing chips handled by "master".
|
* @chip-select: Chipselect, distinguishing chips handled by "master".
|
||||||
* @mode: The spi mode defines how data is clocked out and in.
|
* @mode: The spi mode defines how data is clocked out and in.
|
||||||
* This may be changed by the device's driver.
|
* This may be changed by the device's driver.
|
||||||
|
* The "active low" default for chipselect mode can be overridden,
|
||||||
|
* as can the "MSB first" default for each word in a transfer.
|
||||||
* @bits_per_word: Data transfers involve one or more words; word sizes
|
* @bits_per_word: Data transfers involve one or more words; word sizes
|
||||||
* like eight or 12 bits are common. In-memory wordsizes are
|
* like eight or 12 bits are common. In-memory wordsizes are
|
||||||
* powers of two bytes (e.g. 20 bit samples use 32 bits).
|
* powers of two bytes (e.g. 20 bit samples use 32 bits).
|
||||||
* This may be changed by the device's driver.
|
* This may be changed by the device's driver, or left at the
|
||||||
|
* default (0) indicating protocol words are eight bit bytes.
|
||||||
|
* The spi_transfer.bits_per_word can override this for each transfer.
|
||||||
* @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
|
||||||
|
@ -65,6 +70,7 @@ struct spi_device {
|
||||||
#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? */
|
||||||
|
#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */
|
||||||
u8 bits_per_word;
|
u8 bits_per_word;
|
||||||
int irq;
|
int irq;
|
||||||
void *controller_state;
|
void *controller_state;
|
||||||
|
@ -73,7 +79,6 @@ struct spi_device {
|
||||||
|
|
||||||
// likely need more hooks for more protocol options affecting how
|
// likely need more hooks for more protocol options affecting how
|
||||||
// the controller talks to each chip, like:
|
// the controller talks to each chip, like:
|
||||||
// - 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
|
// - drop chipselect after each word
|
||||||
|
@ -167,13 +172,13 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
|
||||||
struct spi_master {
|
struct spi_master {
|
||||||
struct class_device cdev;
|
struct class_device cdev;
|
||||||
|
|
||||||
/* other than zero (== assign one dynamically), bus_num is fully
|
/* other than negative (== assign one dynamically), bus_num is fully
|
||||||
* board-specific. usually that simplifies to being SOC-specific.
|
* board-specific. usually that simplifies to being SOC-specific.
|
||||||
* example: one SOC has three SPI controllers, numbered 1..3,
|
* example: one SOC has three SPI controllers, numbered 0..2,
|
||||||
* and one board's schematics might show it using SPI-2. software
|
* and one board's schematics might show it using SPI-2. software
|
||||||
* would normally use bus_num=2 for that controller.
|
* would normally use bus_num=2 for that controller.
|
||||||
*/
|
*/
|
||||||
u16 bus_num;
|
s16 bus_num;
|
||||||
|
|
||||||
/* chipselects will be integral to many controllers; some others
|
/* chipselects will be integral to many controllers; some others
|
||||||
* might use board-specific GPIOs.
|
* might use board-specific GPIOs.
|
||||||
|
@ -268,6 +273,10 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum);
|
||||||
* @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped
|
* @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped
|
||||||
* @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped
|
* @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped
|
||||||
* @len: size of rx and tx buffers (in bytes)
|
* @len: size of rx and tx buffers (in bytes)
|
||||||
|
* @speed_hz: Select a speed other then the device default for this
|
||||||
|
* transfer. If 0 the default (from spi_device) is used.
|
||||||
|
* @bits_per_word: select a bits_per_word other then the device default
|
||||||
|
* for this transfer. If 0 the default (from spi_device) is used.
|
||||||
* @cs_change: affects chipselect after this transfer completes
|
* @cs_change: affects chipselect after this transfer completes
|
||||||
* @delay_usecs: microseconds to delay after this transfer before
|
* @delay_usecs: microseconds to delay after this transfer before
|
||||||
* (optionally) changing the chipselect status, then starting
|
* (optionally) changing the chipselect status, then starting
|
||||||
|
@ -322,7 +331,9 @@ struct spi_transfer {
|
||||||
dma_addr_t rx_dma;
|
dma_addr_t rx_dma;
|
||||||
|
|
||||||
unsigned cs_change:1;
|
unsigned cs_change:1;
|
||||||
|
u8 bits_per_word;
|
||||||
u16 delay_usecs;
|
u16 delay_usecs;
|
||||||
|
u32 speed_hz;
|
||||||
|
|
||||||
struct list_head transfer_list;
|
struct list_head transfer_list;
|
||||||
};
|
};
|
||||||
|
|
|
@ -30,6 +30,12 @@ struct spi_bitbang {
|
||||||
|
|
||||||
struct spi_master *master;
|
struct spi_master *master;
|
||||||
|
|
||||||
|
/* setup_transfer() changes clock and/or wordsize to match settings
|
||||||
|
* for this transfer; zeroes restore defaults from spi_device.
|
||||||
|
*/
|
||||||
|
int (*setup_transfer)(struct spi_device *spi,
|
||||||
|
struct spi_transfer *t);
|
||||||
|
|
||||||
void (*chipselect)(struct spi_device *spi, int is_on);
|
void (*chipselect)(struct spi_device *spi, int is_on);
|
||||||
#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
|
#define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */
|
||||||
#define BITBANG_CS_INACTIVE 0
|
#define BITBANG_CS_INACTIVE 0
|
||||||
|
@ -51,6 +57,8 @@ struct spi_bitbang {
|
||||||
extern int spi_bitbang_setup(struct spi_device *spi);
|
extern int spi_bitbang_setup(struct spi_device *spi);
|
||||||
extern void spi_bitbang_cleanup(const struct spi_device *spi);
|
extern void spi_bitbang_cleanup(const struct spi_device *spi);
|
||||||
extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
|
extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m);
|
||||||
|
extern int spi_bitbang_setup_transfer(struct spi_device *spi,
|
||||||
|
struct spi_transfer *t);
|
||||||
|
|
||||||
/* start or stop queue processing */
|
/* start or stop queue processing */
|
||||||
extern int spi_bitbang_start(struct spi_bitbang *spi);
|
extern int spi_bitbang_start(struct spi_bitbang *spi);
|
||||||
|
|
Loading…
Reference in a new issue