Commit 702c0b04 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next-spi' of git://git.secretlab.ca/git/linux-2.6

* 'next-spi' of git://git.secretlab.ca/git/linux-2.6:
  spi/xilinx: Fix compile error
  spi/davinci: Fix clock prescale factor computation
  spi: move bitbang txrx utility functions to private header
  spi/mpc5121: Add SPI master driver for MPC5121 PSC
  powerpc/mpc5121: move PSC FIFO memory init to platform code
  spi/ep93xx: implemented driver for Cirrus EP93xx SPI controller
  Documentation/spi/* compile warning fix
  spi/omap2_mcspi: Check params before dereference or use
  spi/omap2_mcspi: add turbo mode support
  spi/omap2_mcspi: change default DMA_MIN_BYTES value to 160
  spi/pl022: fix stop queue procedure
  spi/pl022: add support for the PL023 derivate
  spi/pl022: fix up differences between ARM and ST versions
  spi/spi_mpc8xxx: Do not use map_tx_dma to unmap rx_dma
  spi/spi_mpc8xxx: Fix QE mode Litte Endian
  spi/spi_mpc8xxx: fix potential memory corruption.
parents c19eb8f0 bf6a67ee
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 <mach/ep93xx_spi.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));
}
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.
...@@ -58,10 +58,10 @@ static void do_msg(int fd, int len) ...@@ -58,10 +58,10 @@ static void do_msg(int fd, int len)
len = sizeof buf; len = sizeof buf;
buf[0] = 0xaa; buf[0] = 0xaa;
xfer[0].tx_buf = (__u64) buf; xfer[0].tx_buf = (unsigned long)buf;
xfer[0].len = 1; xfer[0].len = 1;
xfer[1].rx_buf = (__u64) buf; xfer[1].rx_buf = (unsigned long) buf;
xfer[1].len = len; xfer[1].len = len;
status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer); status = ioctl(fd, SPI_IOC_MESSAGE(2), xfer);
......
#ifndef __ASM_MACH_EP93XX_SPI_H
#define __ASM_MACH_EP93XX_SPI_H
struct spi_device;
/**
* struct ep93xx_spi_info - EP93xx specific SPI descriptor
* @num_chipselect: number of chip selects on this board, must be
* at least one
*/
struct ep93xx_spi_info {
int num_chipselect;
};
/**
* struct ep93xx_spi_chip_ops - operation callbacks for SPI slave device
* @setup: setup the chip select mechanism
* @cleanup: cleanup the chip select mechanism
* @cs_control: control the device chip select
*/
struct ep93xx_spi_chip_ops {
int (*setup)(struct spi_device *spi);
void (*cleanup)(struct spi_device *spi);
void (*cs_control)(struct spi_device *spi, int value);
};
#endif /* __ASM_MACH_EP93XX_SPI_H */
...@@ -248,6 +248,7 @@ struct mpc52xx_psc_fifo { ...@@ -248,6 +248,7 @@ struct mpc52xx_psc_fifo {
u16 tflwfptr; /* PSC + 0x9e */ u16 tflwfptr; /* PSC + 0x9e */
}; };
#define MPC512x_PSC_FIFO_EOF 0x100
#define MPC512x_PSC_FIFO_RESET_SLICE 0x80 #define MPC512x_PSC_FIFO_RESET_SLICE 0x80
#define MPC512x_PSC_FIFO_ENABLE_SLICE 0x01 #define MPC512x_PSC_FIFO_ENABLE_SLICE 0x01
#define MPC512x_PSC_FIFO_ENABLE_DMA 0x04 #define MPC512x_PSC_FIFO_ENABLE_DMA 0x04
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <asm/prom.h> #include <asm/prom.h>
#include <asm/time.h> #include <asm/time.h>
#include <asm/mpc5121.h> #include <asm/mpc5121.h>
#include <asm/mpc52xx_psc.h>
#include "mpc512x.h" #include "mpc512x.h"
...@@ -95,9 +96,86 @@ void __init mpc512x_declare_of_platform_devices(void) ...@@ -95,9 +96,86 @@ void __init mpc512x_declare_of_platform_devices(void)
} }
} }
#define DEFAULT_FIFO_SIZE 16
static unsigned int __init get_fifo_size(struct device_node *np,
char *prop_name)
{
const unsigned int *fp;
fp = of_get_property(np, prop_name, NULL);
if (fp)
return *fp;
pr_warning("no %s property in %s node, defaulting to %d\n",
prop_name, np->full_name, DEFAULT_FIFO_SIZE);
return DEFAULT_FIFO_SIZE;
}
#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
((u32)(_base) + sizeof(struct mpc52xx_psc)))
/* Init PSC FIFO space for TX and RX slices */
void __init mpc512x_psc_fifo_init(void)
{
struct device_node *np;
void __iomem *psc;
unsigned int tx_fifo_size;
unsigned int rx_fifo_size;
int fifobase = 0; /* current fifo address in 32 bit words */
for_each_compatible_node(np, NULL, "fsl,mpc5121-psc") {
tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
/* size in register is in 4 byte units */
tx_fifo_size /= 4;
rx_fifo_size /= 4;
if (!tx_fifo_size)
tx_fifo_size = 1;
if (!rx_fifo_size)
rx_fifo_size = 1;
psc = of_iomap(np, 0);
if (!psc) {
pr_err("%s: Can't map %s device\n",
__func__, np->full_name);
continue;
}
/* FIFO space is 4KiB, check if requested size is available */
if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
pr_err("%s: no fifo space available for %s\n",
__func__, np->full_name);
iounmap(psc);
/*
* chances are that another device requests less
* fifo space, so we continue.
*/
continue;
}
/* set tx and rx fifo size registers */
out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
fifobase += tx_fifo_size;
out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
fifobase += rx_fifo_size;
/* reset and enable the slices */
out_be32(&FIFOC(psc)->txcmd, 0x80);
out_be32(&FIFOC(psc)->txcmd, 0x01);
out_be32(&FIFOC(psc)->rxcmd, 0x80);
out_be32(&FIFOC(psc)->rxcmd, 0x01);
iounmap(psc);
}
}
void __init mpc512x_init(void) void __init mpc512x_init(void)
{ {
mpc512x_declare_of_platform_devices(); mpc512x_declare_of_platform_devices();
mpc5121_clk_init(); mpc5121_clk_init();
mpc512x_restart_init(); mpc512x_restart_init();
mpc512x_psc_fifo_init();
} }
...@@ -397,34 +397,10 @@ static unsigned long mpc512x_getuartclk(void *p) ...@@ -397,34 +397,10 @@ static unsigned long mpc512x_getuartclk(void *p)
return mpc5xxx_get_bus_frequency(p); return mpc5xxx_get_bus_frequency(p);
} }
#define DEFAULT_FIFO_SIZE 16
static unsigned int __init get_fifo_size(struct device_node *np,
char *fifo_name)
{
const unsigned int *fp;
fp = of_get_property(np, fifo_name, NULL);
if (fp)
return *fp;
pr_warning("no %s property in %s node, defaulting to %d\n",
fifo_name, np->full_name, DEFAULT_FIFO_SIZE);
return DEFAULT_FIFO_SIZE;
}
#define FIFOC(_base) ((struct mpc512x_psc_fifo __iomem *) \
((u32)(_base) + sizeof(struct mpc52xx_psc)))
/* Init PSC FIFO Controller */ /* Init PSC FIFO Controller */
static int __init mpc512x_psc_fifoc_init(void) static int __init mpc512x_psc_fifoc_init(void)
{ {
struct device_node *np; struct device_node *np;
void __iomem *psc;
unsigned int tx_fifo_size;
unsigned int rx_fifo_size;
int fifobase = 0; /* current fifo address in 32 bit words */
np = of_find_compatible_node(NULL, NULL, np = of_find_compatible_node(NULL, NULL,
"fsl,mpc5121-psc-fifo"); "fsl,mpc5121-psc-fifo");
...@@ -447,51 +423,6 @@ static int __init mpc512x_psc_fifoc_init(void) ...@@ -447,51 +423,6 @@ static int __init mpc512x_psc_fifoc_init(void)
return -ENODEV; return -ENODEV;
} }
for_each_compatible_node(np, NULL, "fsl,mpc5121-psc-uart") {
tx_fifo_size = get_fifo_size(np, "fsl,tx-fifo-size");
rx_fifo_size = get_fifo_size(np, "fsl,rx-fifo-size");
/* size in register is in 4 byte units */
tx_fifo_size /= 4;
rx_fifo_size /= 4;
if (!tx_fifo_size)
tx_fifo_size = 1;
if (!rx_fifo_size)
rx_fifo_size = 1;
psc = of_iomap(np, 0);
if (!psc) {
pr_err("%s: Can't map %s device\n",
__func__, np->full_name);
continue;
}
/* FIFO space is 4KiB, check if requested size is available */
if ((fifobase + tx_fifo_size + rx_fifo_size) > 0x1000) {
pr_err("%s: no fifo space available for %s\n",
__func__, np->full_name);
iounmap(psc);
/*
* chances are that another device requests less
* fifo space, so we continue.
*/
continue;
}
/* set tx and rx fifo size registers */
out_be32(&FIFOC(psc)->txsz, (fifobase << 16) | tx_fifo_size);
fifobase += tx_fifo_size;
out_be32(&FIFOC(psc)->rxsz, (fifobase << 16) | rx_fifo_size);
fifobase += rx_fifo_size;
/* reset and enable the slices */
out_be32(&FIFOC(psc)->txcmd, 0x80);
out_be32(&FIFOC(psc)->txcmd, 0x01);
out_be32(&FIFOC(psc)->rxcmd, 0x80);
out_be32(&FIFOC(psc)->rxcmd, 0x01);
iounmap(psc);
}
return 0; return 0;
} }
......
...@@ -117,6 +117,16 @@ config SPI_DAVINCI ...@@ -117,6 +117,16 @@ config SPI_DAVINCI
help help
SPI master controller for DaVinci and DA8xx SPI modules. SPI master controller for DaVinci and DA8xx SPI modules.
config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller"
depends on ARCH_EP93XX
help
This enables using the Cirrus EP93xx SPI controller in master
mode.
To compile this driver as a module, choose M here. The module will be
called ep93xx_spi.
config SPI_GPIO config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master" tristate "GPIO-based bitbanging SPI Master"
depends on GENERIC_GPIO depends on GENERIC_GPIO
...@@ -165,6 +175,13 @@ config SPI_MPC52xx_PSC ...@@ -165,6 +175,13 @@ config SPI_MPC52xx_PSC
This enables using the Freescale MPC52xx Programmable Serial This enables using the Freescale MPC52xx Programmable Serial
Controller in master SPI mode. Controller in master SPI mode.
config SPI_MPC512x_PSC
tristate "Freescale MPC512x PSC SPI controller"
depends on SPI_MASTER && PPC_MPC512x
help
This enables using the Freescale MPC5121 Programmable Serial
Controller in SPI master mode.
config SPI_MPC8xxx config SPI_MPC8xxx
tristate "Freescale MPC8xxx SPI controller" tristate "Freescale MPC8xxx SPI controller"
depends on FSL_SOC depends on FSL_SOC
......
...@@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o ...@@ -21,6 +21,7 @@ obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o
obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.o
obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o obj-$(CONFIG_SPI_DW_PCI) += dw_spi_pci.o
obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o obj-$(CONFIG_SPI_DW_MMIO) += dw_spi_mmio.o
obj-$(CONFIG_SPI_EP93XX) += ep93xx_spi.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
...@@ -30,6 +31,7 @@ obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o ...@@ -30,6 +31,7 @@ obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o
obj-$(CONFIG_SPI_ORION) += orion_spi.o obj-$(CONFIG_SPI_ORION) += orion_spi.o
obj-$(CONFIG_SPI_PL022) += amba-pl022.o obj-$(CONFIG_SPI_PL022) += amba-pl022.o
obj-$(CONFIG_SPI_MPC512x_PSC) += mpc512x_psc_spi.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC52xx) += mpc52xx_spi.o obj-$(CONFIG_SPI_MPC52xx) += mpc52xx_spi.o
obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o obj-$(CONFIG_SPI_MPC8xxx) += spi_mpc8xxx.o
......
This diff is collapsed.
...@@ -301,7 +301,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -301,7 +301,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
struct davinci_spi *davinci_spi; struct davinci_spi *davinci_spi;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
u8 bits_per_word = 0; u8 bits_per_word = 0;
u32 hz = 0, prescale; u32 hz = 0, prescale = 0, clkspeed;
davinci_spi = spi_master_get_devdata(spi->master); davinci_spi = spi_master_get_devdata(spi->master);
pdata = davinci_spi->pdata; pdata = davinci_spi->pdata;
...@@ -338,10 +338,16 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -338,10 +338,16 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f, set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
spi->chip_select); spi->chip_select);
prescale = ((clk_get_rate(davinci_spi->clk) / hz) - 1) & 0xff; clkspeed = clk_get_rate(davinci_spi->clk);
if (hz > clkspeed / 2)
prescale = 1 << 8;
if (hz < clkspeed / 256)
prescale = 255 << 8;
if (!prescale)
prescale = ((clkspeed / hz - 1) << 8) & 0x0000ff00;
clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select); clear_fmt_bits(davinci_spi->base, 0x0000ff00, spi->chip_select);
set_fmt_bits(davinci_spi->base, prescale << 8, spi->chip_select); set_fmt_bits(davinci_spi->base, prescale, spi->chip_select);
return 0; return 0;
} }
......
This diff is collapsed.
This diff is collapsed.
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include <plat/dma.h> #include <plat/dma.h>
#include <plat/clock.h> #include <plat/clock.h>
#include <plat/mcspi.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000 #define OMAP2_MCSPI_MAX_FREQ 48000000
...@@ -113,7 +113,7 @@ struct omap2_mcspi_dma { ...@@ -113,7 +113,7 @@ struct omap2_mcspi_dma {
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and /* use PIO for small transfers, avoiding DMA setup/teardown overhead and
* cache operations; better heuristics consider wordsize and bitrate. * cache operations; better heuristics consider wordsize and bitrate.
*/ */
#define DMA_MIN_BYTES 8 #define DMA_MIN_BYTES 160
struct omap2_mcspi { struct omap2_mcspi {
...@@ -229,6 +229,8 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) ...@@ -229,6 +229,8 @@ static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable)
l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0; l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l); mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
/* Flash post-writes */
mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
} }
static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active)
...@@ -303,11 +305,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -303,11 +305,14 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
unsigned int count, c; unsigned int count, c;
unsigned long base, tx_reg, rx_reg; unsigned long base, tx_reg, rx_reg;
int word_len, data_type, element_count; int word_len, data_type, element_count;
int elements;
u32 l;
u8 * rx; u8 * rx;
const u8 * tx; const u8 * tx;
mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select];
l = mcspi_cached_chconf0(spi);
count = xfer->len; count = xfer->len;
c = count; c = count;
...@@ -346,8 +351,12 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -346,8 +351,12 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
} }
if (rx != NULL) { if (rx != NULL) {
elements = element_count - 1;
if (l & OMAP2_MCSPI_CHCONF_TURBO)
elements--;
omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel, omap_set_dma_transfer_params(mcspi_dma->dma_rx_channel,
data_type, element_count - 1, 1, data_type, elements, 1,
OMAP_DMA_SYNC_ELEMENT, OMAP_DMA_SYNC_ELEMENT,
mcspi_dma->dma_rx_sync_dev, 1); mcspi_dma->dma_rx_sync_dev, 1);
...@@ -379,17 +388,42 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -379,17 +388,42 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
wait_for_completion(&mcspi_dma->dma_rx_completion); wait_for_completion(&mcspi_dma->dma_rx_completion);
dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE); dma_unmap_single(NULL, xfer->rx_dma, count, DMA_FROM_DEVICE);
omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0);
if (l & OMAP2_MCSPI_CHCONF_TURBO) {
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
& OMAP2_MCSPI_CHSTAT_RXS)) {
u32 w;
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
if (word_len <= 8)
((u8 *)xfer->rx_buf)[elements++] = w;
else if (word_len <= 16)
((u16 *)xfer->rx_buf)[elements++] = w;
else /* word_len <= 32 */
((u32 *)xfer->rx_buf)[elements++] = w;
} else {
dev_err(&spi->dev,
"DMA RX penultimate word empty");
count -= (word_len <= 8) ? 2 :
(word_len <= 16) ? 4 :
/* word_len <= 32 */ 8;
omap2_mcspi_set_enable(spi, 1);
return count;
}
}
if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0)
& OMAP2_MCSPI_CHSTAT_RXS)) { & OMAP2_MCSPI_CHSTAT_RXS)) {
u32 w; u32 w;
w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0);
if (word_len <= 8) if (word_len <= 8)
((u8 *)xfer->rx_buf)[element_count - 1] = w; ((u8 *)xfer->rx_buf)[elements] = w;
else if (word_len <= 16) else if (word_len <= 16)
((u16 *)xfer->rx_buf)[element_count - 1] = w; ((u16 *)xfer->rx_buf)[elements] = w;
else /* word_len <= 32 */ else /* word_len <= 32 */
((u32 *)xfer->rx_buf)[element_count - 1] = w; ((u32 *)xfer->rx_buf)[elements] = w;
} else { } else {
dev_err(&spi->dev, "DMA RX last word empty"); dev_err(&spi->dev, "DMA RX last word empty");
count -= (word_len <= 8) ? 1 : count -= (word_len <= 8) ? 1 :
...@@ -433,7 +467,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -433,7 +467,6 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
word_len = cs->word_len; word_len = cs->word_len;
l = mcspi_cached_chconf0(spi); l = mcspi_cached_chconf0(spi);
l &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
/* We store the pre-calculated register addresses on stack to speed /* We store the pre-calculated register addresses on stack to speed
* up the transfer loop. */ * up the transfer loop. */
...@@ -468,11 +501,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -468,11 +501,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
dev_err(&spi->dev, "RXS timed out\n"); dev_err(&spi->dev, "RXS timed out\n");
goto out; goto out;
} }
/* prevent last RX_ONLY read from triggering
* more word i/o: switch to rx+tx if (c == 1 && tx == NULL &&
*/ (l & OMAP2_MCSPI_CHCONF_TURBO)) {
if (c == 0 && tx == NULL) omap2_mcspi_set_enable(spi, 0);
mcspi_write_chconf0(spi, l); *rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %02x\n",
word_len, *(rx - 1));
#endif
if (mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_RXS) < 0) {
dev_err(&spi->dev,
"RXS timed out\n");
goto out;
}
c = 0;
} else if (c == 0 && tx == NULL) {
omap2_mcspi_set_enable(spi, 0);
}
*rx++ = __raw_readl(rx_reg); *rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE #ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %02x\n", dev_dbg(&spi->dev, "read-%d %02x\n",
...@@ -506,11 +554,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -506,11 +554,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
dev_err(&spi->dev, "RXS timed out\n"); dev_err(&spi->dev, "RXS timed out\n");
goto out; goto out;
} }
/* prevent last RX_ONLY read from triggering
* more word i/o: switch to rx+tx if (c == 2 && tx == NULL &&
*/ (l & OMAP2_MCSPI_CHCONF_TURBO)) {
if (c == 0 && tx == NULL) omap2_mcspi_set_enable(spi, 0);
mcspi_write_chconf0(spi, l); *rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %04x\n",
word_len, *(rx - 1));
#endif
if (mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_RXS) < 0) {
dev_err(&spi->dev,
"RXS timed out\n");
goto out;
}
c = 0;
} else if (c == 0 && tx == NULL) {
omap2_mcspi_set_enable(spi, 0);
}
*rx++ = __raw_readl(rx_reg); *rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE #ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %04x\n", dev_dbg(&spi->dev, "read-%d %04x\n",
...@@ -544,11 +607,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -544,11 +607,26 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
dev_err(&spi->dev, "RXS timed out\n"); dev_err(&spi->dev, "RXS timed out\n");
goto out; goto out;
} }
/* prevent last RX_ONLY read from triggering
* more word i/o: switch to rx+tx if (c == 4 && tx == NULL &&
*/ (l & OMAP2_MCSPI_CHCONF_TURBO)) {
if (c == 0 && tx == NULL) omap2_mcspi_set_enable(spi, 0);
mcspi_write_chconf0(spi, l); *rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %08x\n",
word_len, *(rx - 1));
#endif
if (mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_RXS) < 0) {
dev_err(&spi->dev,
"RXS timed out\n");
goto out;
}
c = 0;
} else if (c == 0 && tx == NULL) {
omap2_mcspi_set_enable(spi, 0);
}
*rx++ = __raw_readl(rx_reg); *rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE #ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %08x\n", dev_dbg(&spi->dev, "read-%d %08x\n",
...@@ -568,6 +646,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -568,6 +646,7 @@ omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
dev_err(&spi->dev, "EOT timed out\n"); dev_err(&spi->dev, "EOT timed out\n");
} }
out: out:
omap2_mcspi_set_enable(spi, 1);
return count - c; return count - c;
} }
...@@ -755,7 +834,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) ...@@ -755,7 +834,6 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
struct omap2_mcspi_cs *cs; struct omap2_mcspi_cs *cs;
mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
if (spi->controller_state) { if (spi->controller_state) {
/* Unlink controller state from context save list */ /* Unlink controller state from context save list */
...@@ -765,13 +843,17 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) ...@@ -765,13 +843,17 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
kfree(spi->controller_state); kfree(spi->controller_state);
} }
if (mcspi_dma->dma_rx_channel != -1) { if (spi->chip_select < spi->master->num_chipselect) {
omap_free_dma(mcspi_dma->dma_rx_channel); mcspi_dma = &mcspi->dma_channels[spi->chip_select];
mcspi_dma->dma_rx_channel = -1;
} if (mcspi_dma->dma_rx_channel != -1) {
if (mcspi_dma->dma_tx_channel != -1) { omap_free_dma(mcspi_dma->dma_rx_channel);
omap_free_dma(mcspi_dma->dma_tx_channel); mcspi_dma->dma_rx_channel = -1;
mcspi_dma->dma_tx_channel = -1; }
if (mcspi_dma->dma_tx_channel != -1) {
omap_free_dma(mcspi_dma->dma_tx_channel);
mcspi_dma->dma_tx_channel = -1;
}
} }
} }
...@@ -797,6 +879,7 @@ static void omap2_mcspi_work(struct work_struct *work) ...@@ -797,6 +879,7 @@ static void omap2_mcspi_work(struct work_struct *work)
struct spi_transfer *t = NULL; struct spi_transfer *t = NULL;
int cs_active = 0; int cs_active = 0;
struct omap2_mcspi_cs *cs; struct omap2_mcspi_cs *cs;
struct omap2_mcspi_device_config *cd;
int par_override = 0; int par_override = 0;
int status = 0; int status = 0;
u32 chconf; u32 chconf;
...@@ -809,6 +892,7 @@ static void omap2_mcspi_work(struct work_struct *work) ...@@ -809,6 +892,7 @@ static void omap2_mcspi_work(struct work_struct *work)
spi = m->spi; spi = m->spi;
cs = spi->controller_state; cs = spi->controller_state;
cd = spi->controller_data;
omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 1);
list_for_each_entry(t, &m->transfers, transfer_list) { list_for_each_entry(t, &m->transfers, transfer_list) {
...@@ -832,10 +916,19 @@ static void omap2_mcspi_work(struct work_struct *work) ...@@ -832,10 +916,19 @@ static void omap2_mcspi_work(struct work_struct *work)
chconf = mcspi_cached_chconf0(spi); chconf = mcspi_cached_chconf0(spi);
chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK;
chconf &= ~OMAP2_MCSPI_CHCONF_TURBO;
if (t->tx_buf == NULL) if (t->tx_buf == NULL)
chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY;
else if (t->rx_buf == NULL) else if (t->rx_buf == NULL)
chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
if (cd && cd->turbo_mode && t->tx_buf == NULL) {
/* Turbo mode is for more than one word */
if (t->len > ((cs->word_len + 7) >> 3))
chconf |= OMAP2_MCSPI_CHCONF_TURBO;
}
mcspi_write_chconf0(spi, chconf); mcspi_write_chconf0(spi, chconf);
if (t->len) { if (t->len) {
......
/*
* Mix this utility code with some glue code to get one of several types of
* simple SPI master driver. Two do polled word-at-a-time I/O:
*
* - GPIO/parport bitbangers. Provide chipselect() and txrx_word[](),
* expanding the per-word routines from the inline templates below.
*
* - Drivers for controllers resembling bare shift registers. Provide
* chipselect() and txrx_word[](), with custom setup()/cleanup() methods
* that use your controller's clock and chipselect registers.
*
* Some hardware works well with requests at spi_transfer scope:
*
* - Drivers leveraging smarter hardware, with fifos or DMA; or for half
* duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(),
* and custom setup()/cleanup() methods.
*/
/*
* The code that knows what GPIO pins do what should have declared four
* functions, ideally as inlines, before including this header:
*
* void setsck(struct spi_device *, int is_on);
* void setmosi(struct spi_device *, int is_on);
* int getmiso(struct spi_device *);
* void spidelay(unsigned);
*
* setsck()'s is_on parameter is a zero/nonzero boolean.
*
* setmosi()'s is_on parameter is a zero/nonzero boolean.
*
* getmiso() is required to return 0 or 1 only. Any other value is invalid
* and will result in improper operation.
*
* A non-inlined routine would call bitbang_txrx_*() routines. The
* main loop could easily compile down to a handful of instructions,
* especially if the delay is a NOP (to run at peak speed).
*
* Since this is software, the timings may not be exactly what your board's
* chips need ... there may be several reasons you'd need to tweak timings
* in these routines, not just make to make it faster or slower to match a
* particular CPU clock rate.
*/
static inline u32
bitbang_txrx_be_cpha0(struct spi_device *spi,
unsigned nsecs, unsigned cpol,
u32 word, u8 bits)
{
/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
/* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on trailing edge */
setmosi(spi, word & (1 << 31));
spidelay(nsecs); /* T(setup) */
setsck(spi, !cpol);
spidelay(nsecs);
/* sample MSB (from slave) on leading edge */
word <<= 1;
word |= getmiso(spi);
setsck(spi, cpol);
}
return word;
}
static inline u32
bitbang_txrx_be_cpha1(struct spi_device *spi,
unsigned nsecs, unsigned cpol,
u32 word, u8 bits)
{
/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
/* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on leading edge */
setsck(spi, !cpol);
setmosi(spi, word & (1 << 31));
spidelay(nsecs); /* T(setup) */
setsck(spi, cpol);
spidelay(nsecs);
/* sample MSB (from slave) on trailing edge */
word <<= 1;
word |= getmiso(spi);
}
return word;
}
...@@ -149,8 +149,7 @@ static void butterfly_chipselect(struct spi_device *spi, int value) ...@@ -149,8 +149,7 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
#define spidelay(X) do{}while(0) #define spidelay(X) do{}while(0)
//#define spidelay ndelay //#define spidelay ndelay
#define EXPAND_BITBANG_TXRX #include "spi_bitbang_txrx.h"
#include <linux/spi/spi_bitbang.h>
static u32 static u32
butterfly_txrx_word_mode0(struct spi_device *spi, butterfly_txrx_word_mode0(struct spi_device *spi,
......
...@@ -127,8 +127,7 @@ static inline int getmiso(const struct spi_device *spi) ...@@ -127,8 +127,7 @@ static inline int getmiso(const struct spi_device *spi)
*/ */
#define spidelay(nsecs) do {} while (0) #define spidelay(nsecs) do {} while (0)
#define EXPAND_BITBANG_TXRX #include "spi_bitbang_txrx.h"
#include <linux/spi/spi_bitbang.h>
/* /*
* These functions can leverage inline expansion of GPIO calls to shrink * These functions can leverage inline expansion of GPIO calls to shrink
......
...@@ -174,8 +174,7 @@ static inline int getmiso(struct spi_device *s) ...@@ -174,8 +174,7 @@ static inline int getmiso(struct spi_device *s)
} }
/*--------------------------------------------------------------------*/ /*--------------------------------------------------------------------*/
#define EXPAND_BITBANG_TXRX 1 #include "spi_bitbang_txrx.h"
#include <linux/spi/spi_bitbang.h>
static void lm70_chipselect(struct spi_device *spi, int value) static void lm70_chipselect(struct spi_device *spi, int value)
{ {
......
...@@ -241,7 +241,6 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi) ...@@ -241,7 +241,6 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
/* Turn off SPI unit prior changing mode */ /* Turn off SPI unit prior changing mode */
mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE); mpc8xxx_spi_write_reg(mode, cs->hw_mode & ~SPMODE_ENABLE);
mpc8xxx_spi_write_reg(mode, cs->hw_mode);
/* When in CPM mode, we need to reinit tx and rx. */ /* When in CPM mode, we need to reinit tx and rx. */
if (mspi->flags & SPI_CPM_MODE) { if (mspi->flags & SPI_CPM_MODE) {
...@@ -258,7 +257,7 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi) ...@@ -258,7 +257,7 @@ static void mpc8xxx_spi_change_mode(struct spi_device *spi)
} }
} }
} }
mpc8xxx_spi_write_reg(mode, cs->hw_mode);
local_irq_restore(flags); local_irq_restore(flags);
} }
...@@ -287,36 +286,12 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value) ...@@ -287,36 +286,12 @@ static void mpc8xxx_spi_chipselect(struct spi_device *spi, int value)
} }
} }
static static int
int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) mspi_apply_cpu_mode_quirks(struct spi_mpc8xxx_cs *cs,
struct spi_device *spi,
struct mpc8xxx_spi *mpc8xxx_spi,
int bits_per_word)
{ {
struct mpc8xxx_spi *mpc8xxx_spi;
u8 bits_per_word, pm;
u32 hz;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
mpc8xxx_spi = spi_master_get_devdata(spi->master);
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;
/* Make sure its a bit width we support [4..16, 32] */
if ((bits_per_word < 4)
|| ((bits_per_word > 16) && (bits_per_word != 32)))
return -EINVAL;
if (!hz)
hz = spi->max_speed_hz;
cs->rx_shift = 0; cs->rx_shift = 0;
cs->tx_shift = 0; cs->tx_shift = 0;
if (bits_per_word <= 8) { if (bits_per_word <= 8) {
...@@ -340,19 +315,82 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -340,19 +315,82 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
return -EINVAL; return -EINVAL;
if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE && if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE &&
spi->mode & SPI_LSB_FIRST) { spi->mode & SPI_LSB_FIRST) {
cs->tx_shift = 0; cs->tx_shift = 0;
if (bits_per_word <= 8) if (bits_per_word <= 8)
cs->rx_shift = 8; cs->rx_shift = 8;
else else
cs->rx_shift = 0; cs->rx_shift = 0;
} }
mpc8xxx_spi->rx_shift = cs->rx_shift; mpc8xxx_spi->rx_shift = cs->rx_shift;
mpc8xxx_spi->tx_shift = cs->tx_shift; mpc8xxx_spi->tx_shift = cs->tx_shift;
mpc8xxx_spi->get_rx = cs->get_rx; mpc8xxx_spi->get_rx = cs->get_rx;
mpc8xxx_spi->get_tx = cs->get_tx; mpc8xxx_spi->get_tx = cs->get_tx;
return bits_per_word;
}
static int
mspi_apply_qe_mode_quirks(struct spi_mpc8xxx_cs *cs,
struct spi_device *spi,
int bits_per_word)
{
/* QE uses Little Endian for words > 8
* so transform all words > 8 into 8 bits
* Unfortnatly that doesn't work for LSB so
* reject these for now */
/* Note: 32 bits word, LSB works iff
* tfcr/rfcr is set to CPMFCR_GBL */
if (spi->mode & SPI_LSB_FIRST &&
bits_per_word > 8)
return -EINVAL;
if (bits_per_word > 8)
return 8; /* pretend its 8 bits */
return bits_per_word;
}
static
int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
{
struct mpc8xxx_spi *mpc8xxx_spi;
int bits_per_word;
u8 pm;
u32 hz;
struct spi_mpc8xxx_cs *cs = spi->controller_state;
mpc8xxx_spi = spi_master_get_devdata(spi->master);
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;
/* Make sure its a bit width we support [4..16, 32] */
if ((bits_per_word < 4)
|| ((bits_per_word > 16) && (bits_per_word != 32)))
return -EINVAL;
if (!hz)
hz = spi->max_speed_hz;
if (!(mpc8xxx_spi->flags & SPI_CPM_MODE))
bits_per_word = mspi_apply_cpu_mode_quirks(cs, spi,
mpc8xxx_spi,
bits_per_word);
else if (mpc8xxx_spi->flags & SPI_QE)
bits_per_word = mspi_apply_qe_mode_quirks(cs, spi,
bits_per_word);
if (bits_per_word < 0)
return bits_per_word;
if (bits_per_word == 32) if (bits_per_word == 32)
bits_per_word = 0; bits_per_word = 0;
else else
...@@ -438,7 +476,7 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi, ...@@ -438,7 +476,7 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
dev_err(dev, "unable to map tx dma\n"); dev_err(dev, "unable to map tx dma\n");
return -ENOMEM; return -ENOMEM;
} }
} else { } else if (t->tx_buf) {
mspi->tx_dma = t->tx_dma; mspi->tx_dma = t->tx_dma;
} }
...@@ -449,7 +487,7 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi, ...@@ -449,7 +487,7 @@ static int mpc8xxx_spi_cpm_bufs(struct mpc8xxx_spi *mspi,
dev_err(dev, "unable to map rx dma\n"); dev_err(dev, "unable to map rx dma\n");
goto err_rx_dma; goto err_rx_dma;
} }
} else { } else if (t->rx_buf) {
mspi->rx_dma = t->rx_dma; mspi->rx_dma = t->rx_dma;
} }
...@@ -477,7 +515,7 @@ static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi) ...@@ -477,7 +515,7 @@ static void mpc8xxx_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
if (mspi->map_tx_dma) if (mspi->map_tx_dma)
dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE); dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
if (mspi->map_tx_dma) if (mspi->map_rx_dma)
dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE); dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
mspi->xfer_in_progress = NULL; mspi->xfer_in_progress = NULL;
} }
......
...@@ -58,8 +58,7 @@ static inline u32 getmiso(struct spi_device *dev) ...@@ -58,8 +58,7 @@ static inline u32 getmiso(struct spi_device *dev)
#define spidelay(x) ndelay(x) #define spidelay(x) ndelay(x)
#define EXPAND_BITBANG_TXRX #include "spi_bitbang_txrx.h"
#include <linux/spi/spi_bitbang.h>
static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi, static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi,
......
...@@ -78,8 +78,7 @@ static inline u32 getmiso(struct spi_device *dev) ...@@ -78,8 +78,7 @@ static inline u32 getmiso(struct spi_device *dev)
#define spidelay(x) ndelay(x) #define spidelay(x) ndelay(x)
#define EXPAND_BITBANG_TXRX #include "spi_bitbang_txrx.h"
#include <linux/spi/spi_bitbang.h>
static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi, static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits) unsigned nsecs, u32 word, u8 bits)
......
...@@ -48,13 +48,13 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev, ...@@ -48,13 +48,13 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
const u32 *prop; const u32 *prop;
int len; int len;
rc = of_address_to_resource(ofdev->node, 0, &r_mem); rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
if (rc) { if (rc) {
dev_warn(&ofdev->dev, "invalid address\n"); dev_warn(&ofdev->dev, "invalid address\n");
return rc; return rc;
} }
rc = of_irq_to_resource(ofdev->node, 0, &r_irq); rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq);
if (rc == NO_IRQ) { if (rc == NO_IRQ) {
dev_warn(&ofdev->dev, "no IRQ found\n"); dev_warn(&ofdev->dev, "no IRQ found\n");
return -ENODEV; return -ENODEV;
...@@ -67,7 +67,7 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev, ...@@ -67,7 +67,7 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
return -ENOMEM; return -ENOMEM;
/* number of slave select bits is required */ /* number of slave select bits is required */
prop = of_get_property(ofdev->node, "xlnx,num-ss-bits", &len); prop = of_get_property(ofdev->dev.of_node, "xlnx,num-ss-bits", &len);
if (!prop || len < sizeof(*prop)) { if (!prop || len < sizeof(*prop)) {
dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n"); dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
return -EINVAL; return -EINVAL;
...@@ -81,7 +81,7 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev, ...@@ -81,7 +81,7 @@ static int __devinit xilinx_spi_of_probe(struct of_device *ofdev,
dev_set_drvdata(&ofdev->dev, master); dev_set_drvdata(&ofdev->dev, master);
/* Add any subnodes on the SPI bus */ /* Add any subnodes on the SPI bus */
of_register_spi_devices(master, ofdev->node); of_register_spi_devices(master, ofdev->dev.of_node);
return 0; return 0;
} }
......
...@@ -71,6 +71,7 @@ struct ssp_clock_params { ...@@ -71,6 +71,7 @@ struct ssp_clock_params {
/** /**
* enum ssp_rx_endian - endianess of Rx FIFO Data * enum ssp_rx_endian - endianess of Rx FIFO Data
* this feature is only available in ST versionf of PL022
*/ */
enum ssp_rx_endian { enum ssp_rx_endian {
SSP_RX_MSB, SSP_RX_MSB,
...@@ -181,7 +182,8 @@ enum ssp_microwire_wait_state { ...@@ -181,7 +182,8 @@ enum ssp_microwire_wait_state {
}; };
/** /**
* enum Microwire - whether Full/Half Duplex * enum ssp_duplex - whether Full/Half Duplex on microwire, only
* available in the ST Micro variant.
* @SSP_MICROWIRE_CHANNEL_FULL_DUPLEX: SSPTXD becomes bi-directional, * @SSP_MICROWIRE_CHANNEL_FULL_DUPLEX: SSPTXD becomes bi-directional,
* SSPRXD not used * SSPRXD not used
* @SSP_MICROWIRE_CHANNEL_HALF_DUPLEX: SSPTXD is an output, SSPRXD is * @SSP_MICROWIRE_CHANNEL_HALF_DUPLEX: SSPTXD is an output, SSPRXD is
...@@ -192,6 +194,31 @@ enum ssp_duplex { ...@@ -192,6 +194,31 @@ enum ssp_duplex {
SSP_MICROWIRE_CHANNEL_HALF_DUPLEX SSP_MICROWIRE_CHANNEL_HALF_DUPLEX
}; };
/**
* enum ssp_clkdelay - an optional clock delay on the feedback clock
* only available in the ST Micro PL023 variant.
* @SSP_FEEDBACK_CLK_DELAY_NONE: no delay, the data coming in from the
* slave is sampled directly
* @SSP_FEEDBACK_CLK_DELAY_1T: the incoming slave data is sampled with
* a delay of T-dt
* @SSP_FEEDBACK_CLK_DELAY_2T: dito with a delay if 2T-dt
* @SSP_FEEDBACK_CLK_DELAY_3T: dito with a delay if 3T-dt
* @SSP_FEEDBACK_CLK_DELAY_4T: dito with a delay if 4T-dt
* @SSP_FEEDBACK_CLK_DELAY_5T: dito with a delay if 5T-dt
* @SSP_FEEDBACK_CLK_DELAY_6T: dito with a delay if 6T-dt
* @SSP_FEEDBACK_CLK_DELAY_7T: dito with a delay if 7T-dt
*/
enum ssp_clkdelay {
SSP_FEEDBACK_CLK_DELAY_NONE,
SSP_FEEDBACK_CLK_DELAY_1T,
SSP_FEEDBACK_CLK_DELAY_2T,
SSP_FEEDBACK_CLK_DELAY_3T,
SSP_FEEDBACK_CLK_DELAY_4T,
SSP_FEEDBACK_CLK_DELAY_5T,
SSP_FEEDBACK_CLK_DELAY_6T,
SSP_FEEDBACK_CLK_DELAY_7T
};
/** /**
* CHIP select/deselect commands * CHIP select/deselect commands
*/ */
...@@ -235,6 +262,8 @@ struct pl022_ssp_controller { ...@@ -235,6 +262,8 @@ struct pl022_ssp_controller {
* @ctrl_len: Microwire interface: Control length * @ctrl_len: Microwire interface: Control length
* @wait_state: Microwire interface: Wait state * @wait_state: Microwire interface: Wait state
* @duplex: Microwire interface: Full/Half duplex * @duplex: Microwire interface: Full/Half duplex
* @clkdelay: on the PL023 variant, the delay in feeback clock cycles
* before sampling the incoming line
* @cs_control: function pointer to board-specific function to * @cs_control: function pointer to board-specific function to
* assert/deassert I/O port to control HW generation of devices chip-select. * assert/deassert I/O port to control HW generation of devices chip-select.
* @dma_xfer_type: Type of DMA xfer (Mem-to-periph or Periph-to-Periph) * @dma_xfer_type: Type of DMA xfer (Mem-to-periph or Periph-to-Periph)
...@@ -258,6 +287,7 @@ struct pl022_config_chip { ...@@ -258,6 +287,7 @@ struct pl022_config_chip {
enum ssp_microwire_ctrl_len ctrl_len; enum ssp_microwire_ctrl_len ctrl_len;
enum ssp_microwire_wait_state wait_state; enum ssp_microwire_wait_state wait_state;
enum ssp_duplex duplex; enum ssp_duplex duplex;
enum ssp_clkdelay clkdelay;
void (*cs_control) (u32 control); void (*cs_control) (u32 control);
}; };
......
#ifndef __SPI_BITBANG_H #ifndef __SPI_BITBANG_H
#define __SPI_BITBANG_H #define __SPI_BITBANG_H
/*
* Mix this utility code with some glue code to get one of several types of
* simple SPI master driver. Two do polled word-at-a-time I/O:
*
* - GPIO/parport bitbangers. Provide chipselect() and txrx_word[](),
* expanding the per-word routines from the inline templates below.
*
* - Drivers for controllers resembling bare shift registers. Provide
* chipselect() and txrx_word[](), with custom setup()/cleanup() methods
* that use your controller's clock and chipselect registers.
*
* Some hardware works well with requests at spi_transfer scope:
*
* - Drivers leveraging smarter hardware, with fifos or DMA; or for half
* duplex (MicroWire) controllers. Provide chipselect() and txrx_bufs(),
* and custom setup()/cleanup() methods.
*/
#include <linux/workqueue.h> #include <linux/workqueue.h>
struct spi_bitbang { struct spi_bitbang {
...@@ -68,86 +50,3 @@ extern int spi_bitbang_start(struct spi_bitbang *spi); ...@@ -68,86 +50,3 @@ extern int spi_bitbang_start(struct spi_bitbang *spi);
extern int spi_bitbang_stop(struct spi_bitbang *spi); extern int spi_bitbang_stop(struct spi_bitbang *spi);
#endif /* __SPI_BITBANG_H */ #endif /* __SPI_BITBANG_H */
/*-------------------------------------------------------------------------*/
#ifdef EXPAND_BITBANG_TXRX
/*
* The code that knows what GPIO pins do what should have declared four
* functions, ideally as inlines, before #defining EXPAND_BITBANG_TXRX
* and including this header:
*
* void setsck(struct spi_device *, int is_on);
* void setmosi(struct spi_device *, int is_on);
* int getmiso(struct spi_device *);
* void spidelay(unsigned);
*
* setsck()'s is_on parameter is a zero/nonzero boolean.
*
* setmosi()'s is_on parameter is a zero/nonzero boolean.
*
* getmiso() is required to return 0 or 1 only. Any other value is invalid
* and will result in improper operation.
*
* A non-inlined routine would call bitbang_txrx_*() routines. The
* main loop could easily compile down to a handful of instructions,
* especially if the delay is a NOP (to run at peak speed).
*
* Since this is software, the timings may not be exactly what your board's
* chips need ... there may be several reasons you'd need to tweak timings
* in these routines, not just make to make it faster or slower to match a
* particular CPU clock rate.
*/
static inline u32
bitbang_txrx_be_cpha0(struct spi_device *spi,
unsigned nsecs, unsigned cpol,
u32 word, u8 bits)
{
/* if (cpol == 0) this is SPI_MODE_0; else this is SPI_MODE_2 */
/* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on trailing edge */
setmosi(spi, word & (1 << 31));
spidelay(nsecs); /* T(setup) */
setsck(spi, !cpol);
spidelay(nsecs);
/* sample MSB (from slave) on leading edge */
word <<= 1;
word |= getmiso(spi);
setsck(spi, cpol);
}
return word;
}
static inline u32
bitbang_txrx_be_cpha1(struct spi_device *spi,
unsigned nsecs, unsigned cpol,
u32 word, u8 bits)
{
/* if (cpol == 0) this is SPI_MODE_1; else this is SPI_MODE_3 */
/* clock starts at inactive polarity */
for (word <<= (32 - bits); likely(bits); bits--) {
/* setup MSB (to slave) on leading edge */
setsck(spi, !cpol);
setmosi(spi, word & (1 << 31));
spidelay(nsecs); /* T(setup) */
setsck(spi, cpol);
spidelay(nsecs);
/* sample MSB (from slave) on trailing edge */
word <<= 1;
word |= getmiso(spi);
}
return word;
}
#endif /* EXPAND_BITBANG_TXRX */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment