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
......
...@@ -102,13 +102,21 @@ ...@@ -102,13 +102,21 @@
/* /*
* SSP Control Register 0 - SSP_CR0 * SSP Control Register 0 - SSP_CR0
*/ */
#define SSP_CR0_MASK_DSS (0x1FUL << 0) #define SSP_CR0_MASK_DSS (0x0FUL << 0)
#define SSP_CR0_MASK_HALFDUP (0x1UL << 5) #define SSP_CR0_MASK_FRF (0x3UL << 4)
#define SSP_CR0_MASK_SPO (0x1UL << 6) #define SSP_CR0_MASK_SPO (0x1UL << 6)
#define SSP_CR0_MASK_SPH (0x1UL << 7) #define SSP_CR0_MASK_SPH (0x1UL << 7)
#define SSP_CR0_MASK_SCR (0xFFUL << 8) #define SSP_CR0_MASK_SCR (0xFFUL << 8)
#define SSP_CR0_MASK_CSS (0x1FUL << 16)
#define SSP_CR0_MASK_FRF (0x3UL << 21) /*
* The ST version of this block moves som bits
* in SSP_CR0 and extends it to 32 bits
*/
#define SSP_CR0_MASK_DSS_ST (0x1FUL << 0)
#define SSP_CR0_MASK_HALFDUP_ST (0x1UL << 5)
#define SSP_CR0_MASK_CSS_ST (0x1FUL << 16)
#define SSP_CR0_MASK_FRF_ST (0x3UL << 21)
/* /*
* SSP Control Register 0 - SSP_CR1 * SSP Control Register 0 - SSP_CR1
...@@ -117,16 +125,18 @@ ...@@ -117,16 +125,18 @@
#define SSP_CR1_MASK_SSE (0x1UL << 1) #define SSP_CR1_MASK_SSE (0x1UL << 1)
#define SSP_CR1_MASK_MS (0x1UL << 2) #define SSP_CR1_MASK_MS (0x1UL << 2)
#define SSP_CR1_MASK_SOD (0x1UL << 3) #define SSP_CR1_MASK_SOD (0x1UL << 3)
#define SSP_CR1_MASK_RENDN (0x1UL << 4)
#define SSP_CR1_MASK_TENDN (0x1UL << 5)
#define SSP_CR1_MASK_MWAIT (0x1UL << 6)
#define SSP_CR1_MASK_RXIFLSEL (0x7UL << 7)
#define SSP_CR1_MASK_TXIFLSEL (0x7UL << 10)
/* /*
* SSP Data Register - SSP_DR * The ST version of this block adds some bits
* in SSP_CR1
*/ */
#define SSP_DR_MASK_DATA 0xFFFFFFFF #define SSP_CR1_MASK_RENDN_ST (0x1UL << 4)
#define SSP_CR1_MASK_TENDN_ST (0x1UL << 5)
#define SSP_CR1_MASK_MWAIT_ST (0x1UL << 6)
#define SSP_CR1_MASK_RXIFLSEL_ST (0x7UL << 7)
#define SSP_CR1_MASK_TXIFLSEL_ST (0x7UL << 10)
/* This one is only in the PL023 variant */
#define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13)
/* /*
* SSP Status Register - SSP_SR * SSP Status Register - SSP_SR
...@@ -260,8 +270,8 @@ ...@@ -260,8 +270,8 @@
/* /*
* SSP Clock Defaults * SSP Clock Defaults
*/ */
#define NMDK_SSP_DEFAULT_CLKRATE 0x2 #define SSP_DEFAULT_CLKRATE 0x2
#define NMDK_SSP_DEFAULT_PRESCALE 0x40 #define SSP_DEFAULT_PRESCALE 0x40
/* /*
* SSP Clock Parameter ranges * SSP Clock Parameter ranges
...@@ -307,16 +317,22 @@ enum ssp_writing { ...@@ -307,16 +317,22 @@ enum ssp_writing {
* @fifodepth: depth of FIFOs (both) * @fifodepth: depth of FIFOs (both)
* @max_bpw: maximum number of bits per word * @max_bpw: maximum number of bits per word
* @unidir: supports unidirection transfers * @unidir: supports unidirection transfers
* @extended_cr: 32 bit wide control register 0 with extra
* features and extra features in CR1 as found in the ST variants
* @pl023: supports a subset of the ST extensions called "PL023"
*/ */
struct vendor_data { struct vendor_data {
int fifodepth; int fifodepth;
int max_bpw; int max_bpw;
bool unidir; bool unidir;
bool extended_cr;
bool pl023;
}; };
/** /**
* struct pl022 - This is the private SSP driver data structure * struct pl022 - This is the private SSP driver data structure
* @adev: AMBA device model hookup * @adev: AMBA device model hookup
* @vendor: Vendor data for the IP block
* @phybase: The physical memory where the SSP device resides * @phybase: The physical memory where the SSP device resides
* @virtbase: The virtual memory where the SSP is mapped * @virtbase: The virtual memory where the SSP is mapped
* @master: SPI framework hookup * @master: SPI framework hookup
...@@ -369,7 +385,8 @@ struct pl022 { ...@@ -369,7 +385,8 @@ struct pl022 {
/** /**
* struct chip_data - To maintain runtime state of SSP for each client chip * struct chip_data - To maintain runtime state of SSP for each client chip
* @cr0: Value of control register CR0 of SSP * @cr0: Value of control register CR0 of SSP - on later ST variants this
* register is 32 bits wide rather than just 16
* @cr1: Value of control register CR1 of SSP * @cr1: Value of control register CR1 of SSP
* @dmacr: Value of DMA control Register of SSP * @dmacr: Value of DMA control Register of SSP
* @cpsr: Value of Clock prescale register * @cpsr: Value of Clock prescale register
...@@ -384,7 +401,7 @@ struct pl022 { ...@@ -384,7 +401,7 @@ struct pl022 {
* This would be set according to the current message that would be served * This would be set according to the current message that would be served
*/ */
struct chip_data { struct chip_data {
u16 cr0; u32 cr0;
u16 cr1; u16 cr1;
u16 dmacr; u16 dmacr;
u16 cpsr; u16 cpsr;
...@@ -517,6 +534,9 @@ static void restore_state(struct pl022 *pl022) ...@@ -517,6 +534,9 @@ static void restore_state(struct pl022 *pl022)
{ {
struct chip_data *chip = pl022->cur_chip; struct chip_data *chip = pl022->cur_chip;
if (pl022->vendor->extended_cr)
writel(chip->cr0, SSP_CR0(pl022->virtbase));
else
writew(chip->cr0, SSP_CR0(pl022->virtbase)); writew(chip->cr0, SSP_CR0(pl022->virtbase));
writew(chip->cr1, SSP_CR1(pl022->virtbase)); writew(chip->cr1, SSP_CR1(pl022->virtbase));
writew(chip->dmacr, SSP_DMACR(pl022->virtbase)); writew(chip->dmacr, SSP_DMACR(pl022->virtbase));
...@@ -525,38 +545,70 @@ static void restore_state(struct pl022 *pl022) ...@@ -525,38 +545,70 @@ static void restore_state(struct pl022 *pl022)
writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase));
} }
/**
* load_ssp_default_config - Load default configuration for SSP
* @pl022: SSP driver private data structure
*/
/* /*
* Default SSP Register Values * Default SSP Register Values
*/ */
#define DEFAULT_SSP_REG_CR0 ( \ #define DEFAULT_SSP_REG_CR0 ( \
GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0) | \ GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0) | \
GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP, 5) | \ GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 4) | \
GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
GEN_MASK_BITS(NMDK_SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \ GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \
GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS, 16) | \ )
GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 21) \
/* ST versions have slightly different bit layout */
#define DEFAULT_SSP_REG_CR0_ST ( \
GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \
GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP_ST, 5) | \
GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \
GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS_ST, 16) | \
GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF_ST, 21) \
)
/* The PL023 version is slightly different again */
#define DEFAULT_SSP_REG_CR0_ST_PL023 ( \
GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \
GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \
GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \
GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \
) )
#define DEFAULT_SSP_REG_CR1 ( \ #define DEFAULT_SSP_REG_CR1 ( \
GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \ GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \
GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) \
)
/* ST versions extend this register to use all 16 bits */
#define DEFAULT_SSP_REG_CR1_ST ( \
DEFAULT_SSP_REG_CR1 | \
GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \
GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \
GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT_ST, 6) |\
GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \
GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) \
)
/*
* The PL023 variant has further differences: no loopback mode, no microwire
* support, and a new clock feedback delay setting.
*/
#define DEFAULT_SSP_REG_CR1_ST_PL023 ( \
GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \ GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \
GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \ GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \
GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \ GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \
GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN, 4) | \ GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \
GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN, 5) | \ GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \
GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT, 6) |\ GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \
GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL, 7) | \ GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) | \
GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL, 10) \ GEN_MASK_BITS(SSP_FEEDBACK_CLK_DELAY_NONE, SSP_CR1_MASK_FBCLKDEL_ST, 13) \
) )
#define DEFAULT_SSP_REG_CPSR ( \ #define DEFAULT_SSP_REG_CPSR ( \
GEN_MASK_BITS(NMDK_SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \ GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \
) )
#define DEFAULT_SSP_REG_DMACR (\ #define DEFAULT_SSP_REG_DMACR (\
...@@ -564,11 +616,22 @@ static void restore_state(struct pl022 *pl022) ...@@ -564,11 +616,22 @@ static void restore_state(struct pl022 *pl022)
GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \ GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \
) )
/**
* load_ssp_default_config - Load default configuration for SSP
* @pl022: SSP driver private data structure
*/
static void load_ssp_default_config(struct pl022 *pl022) static void load_ssp_default_config(struct pl022 *pl022)
{ {
if (pl022->vendor->pl023) {
writel(DEFAULT_SSP_REG_CR0_ST_PL023, SSP_CR0(pl022->virtbase));
writew(DEFAULT_SSP_REG_CR1_ST_PL023, SSP_CR1(pl022->virtbase));
} else if (pl022->vendor->extended_cr) {
writel(DEFAULT_SSP_REG_CR0_ST, SSP_CR0(pl022->virtbase));
writew(DEFAULT_SSP_REG_CR1_ST, SSP_CR1(pl022->virtbase));
} else {
writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase)); writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase));
writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase)); writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase));
}
writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase)); writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase));
writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase)); writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase));
writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase));
...@@ -1008,7 +1071,7 @@ static void do_polling_transfer(void *data) ...@@ -1008,7 +1071,7 @@ static void do_polling_transfer(void *data)
writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE),
SSP_CR1(pl022->virtbase)); SSP_CR1(pl022->virtbase));
dev_dbg(&pl022->adev->dev, "POLLING TRANSFER ONGOING ... \n"); dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
/* FIXME: insert a timeout so we don't hang here indefinately */ /* FIXME: insert a timeout so we don't hang here indefinately */
while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)
readwriter(pl022); readwriter(pl022);
...@@ -1148,7 +1211,6 @@ static int stop_queue(struct pl022 *pl022) ...@@ -1148,7 +1211,6 @@ static int stop_queue(struct pl022 *pl022)
* A wait_queue on the pl022->busy could be used, but then the common * A wait_queue on the pl022->busy could be used, but then the common
* execution path (pump_messages) would be required to call wake_up or * execution path (pump_messages) would be required to call wake_up or
* friends on every SPI message. Do this instead */ * friends on every SPI message. Do this instead */
pl022->run = QUEUE_STOPPED;
while (!list_empty(&pl022->queue) && pl022->busy && limit--) { while (!list_empty(&pl022->queue) && pl022->busy && limit--) {
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
msleep(10); msleep(10);
...@@ -1157,6 +1219,7 @@ static int stop_queue(struct pl022 *pl022) ...@@ -1157,6 +1219,7 @@ static int stop_queue(struct pl022 *pl022)
if (!list_empty(&pl022->queue) || pl022->busy) if (!list_empty(&pl022->queue) || pl022->busy)
status = -EBUSY; status = -EBUSY;
else pl022->run = QUEUE_STOPPED;
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
...@@ -1280,11 +1343,21 @@ static int verify_controller_parameters(struct pl022 *pl022, ...@@ -1280,11 +1343,21 @@ static int verify_controller_parameters(struct pl022 *pl022,
"Wait State is configured incorrectly\n"); "Wait State is configured incorrectly\n");
return -EINVAL; return -EINVAL;
} }
if ((chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) /* Half duplex is only available in the ST Micro version */
if (pl022->vendor->extended_cr) {
if ((chip_info->duplex !=
SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
&& (chip_info->duplex != && (chip_info->duplex !=
SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) { SSP_MICROWIRE_CHANNEL_HALF_DUPLEX))
dev_err(chip_info->dev,
"Microwire duplex mode is configured incorrectly\n");
return -EINVAL;
} else {
if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX)
dev_err(chip_info->dev, dev_err(chip_info->dev,
"DUPLEX is configured incorrectly\n"); "Microwire half duplex mode requested,"
" but this is only available in the"
" ST version of PL022\n");
return -EINVAL; return -EINVAL;
} }
} }
...@@ -1581,22 +1654,49 @@ static int pl022_setup(struct spi_device *spi) ...@@ -1581,22 +1654,49 @@ static int pl022_setup(struct spi_device *spi)
chip->cpsr = chip_info->clk_freq.cpsdvsr; chip->cpsr = chip_info->clk_freq.cpsdvsr;
SSP_WRITE_BITS(chip->cr0, chip_info->data_size, SSP_CR0_MASK_DSS, 0); /* Special setup for the ST micro extended control registers */
SSP_WRITE_BITS(chip->cr0, chip_info->duplex, SSP_CR0_MASK_HALFDUP, 5); if (pl022->vendor->extended_cr) {
if (pl022->vendor->pl023) {
/* These bits are only in the PL023 */
SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay,
SSP_CR1_MASK_FBCLKDEL_ST, 13);
} else {
/* These bits are in the PL022 but not PL023 */
SSP_WRITE_BITS(chip->cr0, chip_info->duplex,
SSP_CR0_MASK_HALFDUP_ST, 5);
SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len,
SSP_CR0_MASK_CSS_ST, 16);
SSP_WRITE_BITS(chip->cr0, chip_info->iface,
SSP_CR0_MASK_FRF_ST, 21);
SSP_WRITE_BITS(chip->cr1, chip_info->wait_state,
SSP_CR1_MASK_MWAIT_ST, 6);
}
SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
SSP_CR0_MASK_DSS_ST, 0);
SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx,
SSP_CR1_MASK_RENDN_ST, 4);
SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx,
SSP_CR1_MASK_TENDN_ST, 5);
SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig,
SSP_CR1_MASK_RXIFLSEL_ST, 7);
SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig,
SSP_CR1_MASK_TXIFLSEL_ST, 10);
} else {
SSP_WRITE_BITS(chip->cr0, chip_info->data_size,
SSP_CR0_MASK_DSS, 0);
SSP_WRITE_BITS(chip->cr0, chip_info->iface,
SSP_CR0_MASK_FRF, 4);
}
/* Stuff that is common for all versions */
SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6); SSP_WRITE_BITS(chip->cr0, chip_info->clk_pol, SSP_CR0_MASK_SPO, 6);
SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7); SSP_WRITE_BITS(chip->cr0, chip_info->clk_phase, SSP_CR0_MASK_SPH, 7);
SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8); SSP_WRITE_BITS(chip->cr0, chip_info->clk_freq.scr, SSP_CR0_MASK_SCR, 8);
SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, SSP_CR0_MASK_CSS, 16); /* Loopback is available on all versions except PL023 */
SSP_WRITE_BITS(chip->cr0, chip_info->iface, SSP_CR0_MASK_FRF, 21); if (!pl022->vendor->pl023)
SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0); SSP_WRITE_BITS(chip->cr1, chip_info->lbm, SSP_CR1_MASK_LBM, 0);
SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1); SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1);
SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2); SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2);
SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3); SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 3);
SSP_WRITE_BITS(chip->cr1, chip_info->endian_rx, SSP_CR1_MASK_RENDN, 4);
SSP_WRITE_BITS(chip->cr1, chip_info->endian_tx, SSP_CR1_MASK_TENDN, 5);
SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, SSP_CR1_MASK_MWAIT, 6);
SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, SSP_CR1_MASK_RXIFLSEL, 7);
SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, SSP_CR1_MASK_TXIFLSEL, 10);
/* Save controller_state */ /* Save controller_state */
spi_set_ctldata(spi, chip); spi_set_ctldata(spi, chip);
...@@ -1809,6 +1909,8 @@ static struct vendor_data vendor_arm = { ...@@ -1809,6 +1909,8 @@ static struct vendor_data vendor_arm = {
.fifodepth = 8, .fifodepth = 8,
.max_bpw = 16, .max_bpw = 16,
.unidir = false, .unidir = false,
.extended_cr = false,
.pl023 = false,
}; };
...@@ -1816,6 +1918,16 @@ static struct vendor_data vendor_st = { ...@@ -1816,6 +1918,16 @@ static struct vendor_data vendor_st = {
.fifodepth = 32, .fifodepth = 32,
.max_bpw = 32, .max_bpw = 32,
.unidir = false, .unidir = false,
.extended_cr = true,
.pl023 = false,
};
static struct vendor_data vendor_st_pl023 = {
.fifodepth = 32,
.max_bpw = 32,
.unidir = false,
.extended_cr = true,
.pl023 = true,
}; };
static struct amba_id pl022_ids[] = { static struct amba_id pl022_ids[] = {
...@@ -1837,6 +1949,18 @@ static struct amba_id pl022_ids[] = { ...@@ -1837,6 +1949,18 @@ static struct amba_id pl022_ids[] = {
.mask = 0xffffffff, .mask = 0xffffffff,
.data = &vendor_st, .data = &vendor_st,
}, },
{
/*
* ST-Ericsson derivative "PL023" (this is not
* an official ARM number), this is a PL022 SSP block
* stripped to SPI mode only, it has 32bit wide
* and 32 locations deep TX/RX FIFO but no extended
* CR0/CR1 register
*/
.id = 0x00080023,
.mask = 0xffffffff,
.data = &vendor_st_pl023,
},
{ 0, 0 }, { 0, 0 },
}; };
......
...@@ -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;
} }
......
/*
* Driver for Cirrus Logic EP93xx SPI controller.
*
* Copyright (c) 2010 Mika Westerberg
*
* Explicit FIFO handling code was inspired by amba-pl022 driver.
*
* Chip select support using other than built-in GPIOs by H. Hartley Sweeten.
*
* For more information about the SPI controller see documentation on Cirrus
* Logic web site:
* http://www.cirrus.com/en/pubs/manual/EP93xx_Users_Guide_UM1.pdf
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <mach/ep93xx_spi.h>
#define SSPCR0 0x0000
#define SSPCR0_MODE_SHIFT 6
#define SSPCR0_SCR_SHIFT 8
#define SSPCR1 0x0004
#define SSPCR1_RIE BIT(0)
#define SSPCR1_TIE BIT(1)
#define SSPCR1_RORIE BIT(2)
#define SSPCR1_LBM BIT(3)
#define SSPCR1_SSE BIT(4)
#define SSPCR1_MS BIT(5)
#define SSPCR1_SOD BIT(6)
#define SSPDR 0x0008
#define SSPSR 0x000c
#define SSPSR_TFE BIT(0)
#define SSPSR_TNF BIT(1)
#define SSPSR_RNE BIT(2)
#define SSPSR_RFF BIT(3)
#define SSPSR_BSY BIT(4)
#define SSPCPSR 0x0010
#define SSPIIR 0x0014
#define SSPIIR_RIS BIT(0)
#define SSPIIR_TIS BIT(1)
#define SSPIIR_RORIS BIT(2)
#define SSPICR SSPIIR
/* timeout in milliseconds */
#define SPI_TIMEOUT 5
/* maximum depth of RX/TX FIFO */
#define SPI_FIFO_SIZE 8
/**
* struct ep93xx_spi - EP93xx SPI controller structure
* @lock: spinlock that protects concurrent accesses to fields @running,
* @current_msg and @msg_queue
* @pdev: pointer to platform device
* @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers
* @irq: IRQ number used by the driver
* @min_rate: minimum clock rate (in Hz) supported by the controller
* @max_rate: maximum clock rate (in Hz) supported by the controller
* @running: is the queue running
* @wq: workqueue used by the driver
* @msg_work: work that is queued for the driver
* @wait: wait here until given transfer is completed
* @msg_queue: queue for the messages
* @current_msg: message that is currently processed (or %NULL if none)
* @tx: current byte in transfer to transmit
* @rx: current byte in transfer to receive
* @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one
* frame decreases this level and sending one frame increases it.
*
* This structure holds EP93xx SPI controller specific information. When
* @running is %true, driver accepts transfer requests from protocol drivers.
* @current_msg is used to hold pointer to the message that is currently
* processed. If @current_msg is %NULL, it means that no processing is going
* on.
*
* Most of the fields are only written once and they can be accessed without
* taking the @lock. Fields that are accessed concurrently are: @current_msg,
* @running, and @msg_queue.
*/
struct ep93xx_spi {
spinlock_t lock;
const struct platform_device *pdev;
struct clk *clk;
void __iomem *regs_base;
int irq;
unsigned long min_rate;
unsigned long max_rate;
bool running;
struct workqueue_struct *wq;
struct work_struct msg_work;
struct completion wait;
struct list_head msg_queue;
struct spi_message *current_msg;
size_t tx;
size_t rx;
size_t fifo_level;
};
/**
* struct ep93xx_spi_chip - SPI device hardware settings
* @spi: back pointer to the SPI device
* @rate: max rate in hz this chip supports
* @div_cpsr: cpsr (pre-scaler) divider
* @div_scr: scr divider
* @dss: bits per word (4 - 16 bits)
* @ops: private chip operations
*
* This structure is used to store hardware register specific settings for each
* SPI device. Settings are written to hardware by function
* ep93xx_spi_chip_setup().
*/
struct ep93xx_spi_chip {
const struct spi_device *spi;
unsigned long rate;
u8 div_cpsr;
u8 div_scr;
u8 dss;
struct ep93xx_spi_chip_ops *ops;
};
/* converts bits per word to CR0.DSS value */
#define bits_per_word_to_dss(bpw) ((bpw) - 1)
static inline void
ep93xx_spi_write_u8(const struct ep93xx_spi *espi, u16 reg, u8 value)
{
__raw_writeb(value, espi->regs_base + reg);
}
static inline u8
ep93xx_spi_read_u8(const struct ep93xx_spi *spi, u16 reg)
{
return __raw_readb(spi->regs_base + reg);
}
static inline void
ep93xx_spi_write_u16(const struct ep93xx_spi *espi, u16 reg, u16 value)
{
__raw_writew(value, espi->regs_base + reg);
}
static inline u16
ep93xx_spi_read_u16(const struct ep93xx_spi *spi, u16 reg)
{
return __raw_readw(spi->regs_base + reg);
}
static int ep93xx_spi_enable(const struct ep93xx_spi *espi)
{
u8 regval;
int err;
err = clk_enable(espi->clk);
if (err)
return err;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval |= SSPCR1_SSE;
ep93xx_spi_write_u8(espi, SSPCR1, regval);
return 0;
}
static void ep93xx_spi_disable(const struct ep93xx_spi *espi)
{
u8 regval;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval &= ~SSPCR1_SSE;
ep93xx_spi_write_u8(espi, SSPCR1, regval);
clk_disable(espi->clk);
}
static void ep93xx_spi_enable_interrupts(const struct ep93xx_spi *espi)
{
u8 regval;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval |= (SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
ep93xx_spi_write_u8(espi, SSPCR1, regval);
}
static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi)
{
u8 regval;
regval = ep93xx_spi_read_u8(espi, SSPCR1);
regval &= ~(SSPCR1_RORIE | SSPCR1_TIE | SSPCR1_RIE);
ep93xx_spi_write_u8(espi, SSPCR1, regval);
}
/**
* ep93xx_spi_calc_divisors() - calculates SPI clock divisors
* @espi: ep93xx SPI controller struct
* @chip: divisors are calculated for this chip
* @rate: desired SPI output clock rate
*
* Function calculates cpsr (clock pre-scaler) and scr divisors based on
* given @rate and places them to @chip->div_cpsr and @chip->div_scr. If,
* for some reason, divisors cannot be calculated nothing is stored and
* %-EINVAL is returned.
*/
static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi,
struct ep93xx_spi_chip *chip,
unsigned long rate)
{
unsigned long spi_clk_rate = clk_get_rate(espi->clk);
int cpsr, scr;
/*
* Make sure that max value is between values supported by the
* controller. Note that minimum value is already checked in
* ep93xx_spi_transfer().
*/
rate = clamp(rate, espi->min_rate, espi->max_rate);
/*
* Calculate divisors so that we can get speed according the
* following formula:
* rate = spi_clock_rate / (cpsr * (1 + scr))
*
* cpsr must be even number and starts from 2, scr can be any number
* between 0 and 255.
*/
for (cpsr = 2; cpsr <= 254; cpsr += 2) {
for (scr = 0; scr <= 255; scr++) {
if ((spi_clk_rate / (cpsr * (scr + 1))) <= rate) {
chip->div_scr = (u8)scr;
chip->div_cpsr = (u8)cpsr;
return 0;
}
}
}
return -EINVAL;
}
static void ep93xx_spi_cs_control(struct spi_device *spi, bool control)
{
struct ep93xx_spi_chip *chip = spi_get_ctldata(spi);
int value = (spi->mode & SPI_CS_HIGH) ? control : !control;
if (chip->ops && chip->ops->cs_control)
chip->ops->cs_control(spi, value);
}
/**
* ep93xx_spi_setup() - setup an SPI device
* @spi: SPI device to setup
*
* This function sets up SPI device mode, speed etc. Can be called multiple
* times for a single device. Returns %0 in case of success, negative error in
* case of failure. When this function returns success, the device is
* deselected.
*/
static int ep93xx_spi_setup(struct spi_device *spi)
{
struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
struct ep93xx_spi_chip *chip;
if (spi->bits_per_word < 4 || spi->bits_per_word > 16) {
dev_err(&espi->pdev->dev, "invalid bits per word %d\n",
spi->bits_per_word);
return -EINVAL;
}
chip = spi_get_ctldata(spi);
if (!chip) {
dev_dbg(&espi->pdev->dev, "initial setup for %s\n",
spi->modalias);
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
chip->spi = spi;
chip->ops = spi->controller_data;
if (chip->ops && chip->ops->setup) {
int ret = chip->ops->setup(spi);
if (ret) {
kfree(chip);
return ret;
}
}
spi_set_ctldata(spi, chip);
}
if (spi->max_speed_hz != chip->rate) {
int err;
err = ep93xx_spi_calc_divisors(espi, chip, spi->max_speed_hz);
if (err != 0) {
spi_set_ctldata(spi, NULL);
kfree(chip);
return err;
}
chip->rate = spi->max_speed_hz;
}
chip->dss = bits_per_word_to_dss(spi->bits_per_word);
ep93xx_spi_cs_control(spi, false);
return 0;
}
/**
* ep93xx_spi_transfer() - queue message to be transferred
* @spi: target SPI device
* @msg: message to be transferred
*
* This function is called by SPI device drivers when they are going to transfer
* a new message. It simply puts the message in the queue and schedules
* workqueue to perform the actual transfer later on.
*
* Returns %0 on success and negative error in case of failure.
*/
static int ep93xx_spi_transfer(struct spi_device *spi, struct spi_message *msg)
{
struct ep93xx_spi *espi = spi_master_get_devdata(spi->master);
struct spi_transfer *t;
unsigned long flags;
if (!msg || !msg->complete)
return -EINVAL;
/* first validate each transfer */
list_for_each_entry(t, &msg->transfers, transfer_list) {
if (t->bits_per_word) {
if (t->bits_per_word < 4 || t->bits_per_word > 16)
return -EINVAL;
}
if (t->speed_hz && t->speed_hz < espi->min_rate)
return -EINVAL;
}
/*
* Now that we own the message, let's initialize it so that it is
* suitable for us. We use @msg->status to signal whether there was
* error in transfer and @msg->state is used to hold pointer to the
* current transfer (or %NULL if no active current transfer).
*/
msg->state = NULL;
msg->status = 0;
msg->actual_length = 0;
spin_lock_irqsave(&espi->lock, flags);
if (!espi->running) {
spin_unlock_irqrestore(&espi->lock, flags);
return -ESHUTDOWN;
}
list_add_tail(&msg->queue, &espi->msg_queue);
queue_work(espi->wq, &espi->msg_work);
spin_unlock_irqrestore(&espi->lock, flags);
return 0;
}
/**
* ep93xx_spi_cleanup() - cleans up master controller specific state
* @spi: SPI device to cleanup
*
* This function releases master controller specific state for given @spi
* device.
*/
static void ep93xx_spi_cleanup(struct spi_device *spi)
{
struct ep93xx_spi_chip *chip;
chip = spi_get_ctldata(spi);
if (chip) {
if (chip->ops && chip->ops->cleanup)
chip->ops->cleanup(spi);
spi_set_ctldata(spi, NULL);
kfree(chip);
}
}
/**
* ep93xx_spi_chip_setup() - configures hardware according to given @chip
* @espi: ep93xx SPI controller struct
* @chip: chip specific settings
*
* This function sets up the actual hardware registers with settings given in
* @chip. Note that no validation is done so make sure that callers validate
* settings before calling this.
*/
static void ep93xx_spi_chip_setup(const struct ep93xx_spi *espi,
const struct ep93xx_spi_chip *chip)
{
u16 cr0;
cr0 = chip->div_scr << SSPCR0_SCR_SHIFT;
cr0 |= (chip->spi->mode & (SPI_CPHA|SPI_CPOL)) << SSPCR0_MODE_SHIFT;
cr0 |= chip->dss;
dev_dbg(&espi->pdev->dev, "setup: mode %d, cpsr %d, scr %d, dss %d\n",
chip->spi->mode, chip->div_cpsr, chip->div_scr, chip->dss);
dev_dbg(&espi->pdev->dev, "setup: cr0 %#x", cr0);
ep93xx_spi_write_u8(espi, SSPCPSR, chip->div_cpsr);
ep93xx_spi_write_u16(espi, SSPCR0, cr0);
}
static inline int bits_per_word(const struct ep93xx_spi *espi)
{
struct spi_message *msg = espi->current_msg;
struct spi_transfer *t = msg->state;
return t->bits_per_word ? t->bits_per_word : msg->spi->bits_per_word;
}
static void ep93xx_do_write(struct ep93xx_spi *espi, struct spi_transfer *t)
{
if (bits_per_word(espi) > 8) {
u16 tx_val = 0;
if (t->tx_buf)
tx_val = ((u16 *)t->tx_buf)[espi->tx];
ep93xx_spi_write_u16(espi, SSPDR, tx_val);
espi->tx += sizeof(tx_val);
} else {
u8 tx_val = 0;
if (t->tx_buf)
tx_val = ((u8 *)t->tx_buf)[espi->tx];
ep93xx_spi_write_u8(espi, SSPDR, tx_val);
espi->tx += sizeof(tx_val);
}
}
static void ep93xx_do_read(struct ep93xx_spi *espi, struct spi_transfer *t)
{
if (bits_per_word(espi) > 8) {
u16 rx_val;
rx_val = ep93xx_spi_read_u16(espi, SSPDR);
if (t->rx_buf)
((u16 *)t->rx_buf)[espi->rx] = rx_val;
espi->rx += sizeof(rx_val);
} else {
u8 rx_val;
rx_val = ep93xx_spi_read_u8(espi, SSPDR);
if (t->rx_buf)
((u8 *)t->rx_buf)[espi->rx] = rx_val;
espi->rx += sizeof(rx_val);
}
}
/**
* ep93xx_spi_read_write() - perform next RX/TX transfer
* @espi: ep93xx SPI controller struct
*
* This function transfers next bytes (or half-words) to/from RX/TX FIFOs. If
* called several times, the whole transfer will be completed. Returns
* %-EINPROGRESS when current transfer was not yet completed otherwise %0.
*
* When this function is finished, RX FIFO should be empty and TX FIFO should be
* full.
*/
static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
{
struct spi_message *msg = espi->current_msg;
struct spi_transfer *t = msg->state;
/* read as long as RX FIFO has frames in it */
while ((ep93xx_spi_read_u8(espi, SSPSR) & SSPSR_RNE)) {
ep93xx_do_read(espi, t);
espi->fifo_level--;
}
/* write as long as TX FIFO has room */
while (espi->fifo_level < SPI_FIFO_SIZE && espi->tx < t->len) {
ep93xx_do_write(espi, t);
espi->fifo_level++;
}
if (espi->rx == t->len) {
msg->actual_length += t->len;
return 0;
}
return -EINPROGRESS;
}
/**
* ep93xx_spi_process_transfer() - processes one SPI transfer
* @espi: ep93xx SPI controller struct
* @msg: current message
* @t: transfer to process
*
* This function processes one SPI transfer given in @t. Function waits until
* transfer is complete (may sleep) and updates @msg->status based on whether
* transfer was succesfully processed or not.
*/
static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
struct spi_message *msg,
struct spi_transfer *t)
{
struct ep93xx_spi_chip *chip = spi_get_ctldata(msg->spi);
msg->state = t;
/*
* Handle any transfer specific settings if needed. We use
* temporary chip settings here and restore original later when
* the transfer is finished.
*/
if (t->speed_hz || t->bits_per_word) {
struct ep93xx_spi_chip tmp_chip = *chip;
if (t->speed_hz) {
int err;
err = ep93xx_spi_calc_divisors(espi, &tmp_chip,
t->speed_hz);
if (err) {
dev_err(&espi->pdev->dev,
"failed to adjust speed\n");
msg->status = err;
return;
}
}
if (t->bits_per_word)
tmp_chip.dss = bits_per_word_to_dss(t->bits_per_word);
/*
* Set up temporary new hw settings for this transfer.
*/
ep93xx_spi_chip_setup(espi, &tmp_chip);
}
espi->rx = 0;
espi->tx = 0;
/*
* Now everything is set up for the current transfer. We prime the TX
* FIFO, enable interrupts, and wait for the transfer to complete.
*/
if (ep93xx_spi_read_write(espi)) {
ep93xx_spi_enable_interrupts(espi);
wait_for_completion(&espi->wait);
}
/*
* In case of error during transmit, we bail out from processing
* the message.
*/
if (msg->status)
return;
/*
* After this transfer is finished, perform any possible
* post-transfer actions requested by the protocol driver.
*/
if (t->delay_usecs) {
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(usecs_to_jiffies(t->delay_usecs));
}
if (t->cs_change) {
if (!list_is_last(&t->transfer_list, &msg->transfers)) {
/*
* In case protocol driver is asking us to drop the
* chipselect briefly, we let the scheduler to handle
* any "delay" here.
*/
ep93xx_spi_cs_control(msg->spi, false);
cond_resched();
ep93xx_spi_cs_control(msg->spi, true);
}
}
if (t->speed_hz || t->bits_per_word)
ep93xx_spi_chip_setup(espi, chip);
}
/*
* ep93xx_spi_process_message() - process one SPI message
* @espi: ep93xx SPI controller struct
* @msg: message to process
*
* This function processes a single SPI message. We go through all transfers in
* the message and pass them to ep93xx_spi_process_transfer(). Chipselect is
* asserted during the whole message (unless per transfer cs_change is set).
*
* @msg->status contains %0 in case of success or negative error code in case of
* failure.
*/
static void ep93xx_spi_process_message(struct ep93xx_spi *espi,
struct spi_message *msg)
{
unsigned long timeout;
struct spi_transfer *t;
int err;
/*
* Enable the SPI controller and its clock.
*/
err = ep93xx_spi_enable(espi);
if (err) {
dev_err(&espi->pdev->dev, "failed to enable SPI controller\n");
msg->status = err;
return;
}
/*
* Just to be sure: flush any data from RX FIFO.
*/
timeout = jiffies + msecs_to_jiffies(SPI_TIMEOUT);
while (ep93xx_spi_read_u16(espi, SSPSR) & SSPSR_RNE) {
if (time_after(jiffies, timeout)) {
dev_warn(&espi->pdev->dev,
"timeout while flushing RX FIFO\n");
msg->status = -ETIMEDOUT;
return;
}
ep93xx_spi_read_u16(espi, SSPDR);
}
/*
* We explicitly handle FIFO level. This way we don't have to check TX
* FIFO status using %SSPSR_TNF bit which may cause RX FIFO overruns.
*/
espi->fifo_level = 0;
/*
* Update SPI controller registers according to spi device and assert
* the chipselect.
*/
ep93xx_spi_chip_setup(espi, spi_get_ctldata(msg->spi));
ep93xx_spi_cs_control(msg->spi, true);
list_for_each_entry(t, &msg->transfers, transfer_list) {
ep93xx_spi_process_transfer(espi, msg, t);
if (msg->status)
break;
}
/*
* Now the whole message is transferred (or failed for some reason). We
* deselect the device and disable the SPI controller.
*/
ep93xx_spi_cs_control(msg->spi, false);
ep93xx_spi_disable(espi);
}
#define work_to_espi(work) (container_of((work), struct ep93xx_spi, msg_work))
/**
* ep93xx_spi_work() - EP93xx SPI workqueue worker function
* @work: work struct
*
* Workqueue worker function. This function is called when there are new
* SPI messages to be processed. Message is taken out from the queue and then
* passed to ep93xx_spi_process_message().
*
* After message is transferred, protocol driver is notified by calling
* @msg->complete(). In case of error, @msg->status is set to negative error
* number, otherwise it contains zero (and @msg->actual_length is updated).
*/
static void ep93xx_spi_work(struct work_struct *work)
{
struct ep93xx_spi *espi = work_to_espi(work);
struct spi_message *msg;
spin_lock_irq(&espi->lock);
if (!espi->running || espi->current_msg ||
list_empty(&espi->msg_queue)) {
spin_unlock_irq(&espi->lock);
return;
}
msg = list_first_entry(&espi->msg_queue, struct spi_message, queue);
list_del_init(&msg->queue);
espi->current_msg = msg;
spin_unlock_irq(&espi->lock);
ep93xx_spi_process_message(espi, msg);
/*
* Update the current message and re-schedule ourselves if there are
* more messages in the queue.
*/
spin_lock_irq(&espi->lock);
espi->current_msg = NULL;
if (espi->running && !list_empty(&espi->msg_queue))
queue_work(espi->wq, &espi->msg_work);
spin_unlock_irq(&espi->lock);
/* notify the protocol driver that we are done with this message */
msg->complete(msg->context);
}
static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
{
struct ep93xx_spi *espi = dev_id;
u8 irq_status = ep93xx_spi_read_u8(espi, SSPIIR);
/*
* If we got ROR (receive overrun) interrupt we know that something is
* wrong. Just abort the message.
*/
if (unlikely(irq_status & SSPIIR_RORIS)) {
/* clear the overrun interrupt */
ep93xx_spi_write_u8(espi, SSPICR, 0);
dev_warn(&espi->pdev->dev,
"receive overrun, aborting the message\n");
espi->current_msg->status = -EIO;
} else {
/*
* Interrupt is either RX (RIS) or TX (TIS). For both cases we
* simply execute next data transfer.
*/
if (ep93xx_spi_read_write(espi)) {
/*
* In normal case, there still is some processing left
* for current transfer. Let's wait for the next
* interrupt then.
*/
return IRQ_HANDLED;
}
}
/*
* Current transfer is finished, either with error or with success. In
* any case we disable interrupts and notify the worker to handle
* any post-processing of the message.
*/
ep93xx_spi_disable_interrupts(espi);
complete(&espi->wait);
return IRQ_HANDLED;
}
static int __init ep93xx_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
struct ep93xx_spi_info *info;
struct ep93xx_spi *espi;
struct resource *res;
int error;
info = pdev->dev.platform_data;
master = spi_alloc_master(&pdev->dev, sizeof(*espi));
if (!master) {
dev_err(&pdev->dev, "failed to allocate spi master\n");
return -ENOMEM;
}
master->setup = ep93xx_spi_setup;
master->transfer = ep93xx_spi_transfer;
master->cleanup = ep93xx_spi_cleanup;
master->bus_num = pdev->id;
master->num_chipselect = info->num_chipselect;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
platform_set_drvdata(pdev, master);
espi = spi_master_get_devdata(master);
espi->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(espi->clk)) {
dev_err(&pdev->dev, "unable to get spi clock\n");
error = PTR_ERR(espi->clk);
goto fail_release_master;
}
spin_lock_init(&espi->lock);
init_completion(&espi->wait);
/*
* Calculate maximum and minimum supported clock rates
* for the controller.
*/
espi->max_rate = clk_get_rate(espi->clk) / 2;
espi->min_rate = clk_get_rate(espi->clk) / (254 * 256);
espi->pdev = pdev;
espi->irq = platform_get_irq(pdev, 0);
if (espi->irq < 0) {
error = -EBUSY;
dev_err(&pdev->dev, "failed to get irq resources\n");
goto fail_put_clock;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "unable to get iomem resource\n");
error = -ENODEV;
goto fail_put_clock;
}
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
dev_err(&pdev->dev, "unable to request iomem resources\n");
error = -EBUSY;
goto fail_put_clock;
}
espi->regs_base = ioremap(res->start, resource_size(res));
if (!espi->regs_base) {
dev_err(&pdev->dev, "failed to map resources\n");
error = -ENODEV;
goto fail_free_mem;
}
error = request_irq(espi->irq, ep93xx_spi_interrupt, 0,
"ep93xx-spi", espi);
if (error) {
dev_err(&pdev->dev, "failed to request irq\n");
goto fail_unmap_regs;
}
espi->wq = create_singlethread_workqueue("ep93xx_spid");
if (!espi->wq) {
dev_err(&pdev->dev, "unable to create workqueue\n");
goto fail_free_irq;
}
INIT_WORK(&espi->msg_work, ep93xx_spi_work);
INIT_LIST_HEAD(&espi->msg_queue);
espi->running = true;
/* make sure that the hardware is disabled */
ep93xx_spi_write_u8(espi, SSPCR1, 0);
error = spi_register_master(master);
if (error) {
dev_err(&pdev->dev, "failed to register SPI master\n");
goto fail_free_queue;
}
dev_info(&pdev->dev, "EP93xx SPI Controller at 0x%08lx irq %d\n",
(unsigned long)res->start, espi->irq);
return 0;
fail_free_queue:
destroy_workqueue(espi->wq);
fail_free_irq:
free_irq(espi->irq, espi);
fail_unmap_regs:
iounmap(espi->regs_base);
fail_free_mem:
release_mem_region(res->start, resource_size(res));
fail_put_clock:
clk_put(espi->clk);
fail_release_master:
spi_master_put(master);
platform_set_drvdata(pdev, NULL);
return error;
}
static int __exit ep93xx_spi_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
struct ep93xx_spi *espi = spi_master_get_devdata(master);
struct resource *res;
spin_lock_irq(&espi->lock);
espi->running = false;
spin_unlock_irq(&espi->lock);
destroy_workqueue(espi->wq);
/*
* Complete remaining messages with %-ESHUTDOWN status.
*/
spin_lock_irq(&espi->lock);
while (!list_empty(&espi->msg_queue)) {
struct spi_message *msg;
msg = list_first_entry(&espi->msg_queue,
struct spi_message, queue);
list_del_init(&msg->queue);
msg->status = -ESHUTDOWN;
spin_unlock_irq(&espi->lock);
msg->complete(msg->context);
spin_lock_irq(&espi->lock);
}
spin_unlock_irq(&espi->lock);
free_irq(espi->irq, espi);
iounmap(espi->regs_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
clk_put(espi->clk);
platform_set_drvdata(pdev, NULL);
spi_unregister_master(master);
return 0;
}
static struct platform_driver ep93xx_spi_driver = {
.driver = {
.name = "ep93xx-spi",
.owner = THIS_MODULE,
},
.remove = __exit_p(ep93xx_spi_remove),
};
static int __init ep93xx_spi_init(void)
{
return platform_driver_probe(&ep93xx_spi_driver, ep93xx_spi_probe);
}
module_init(ep93xx_spi_init);
static void __exit ep93xx_spi_exit(void)
{
platform_driver_unregister(&ep93xx_spi_driver);
}
module_exit(ep93xx_spi_exit);
MODULE_DESCRIPTION("EP93xx SPI Controller driver");
MODULE_AUTHOR("Mika Westerberg <mika.westerberg@iki.fi>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:ep93xx-spi");
/*
* MPC512x PSC in SPI mode driver.
*
* Copyright (C) 2007,2008 Freescale Semiconductor Inc.
* Original port from 52xx driver:
* Hongjun Chen <hong-jun.chen@freescale.com>
*
* Fork of mpc52xx_psc_spi.c:
* Copyright (C) 2006 TOPTICA Photonics AG., Dragos Carp
*
* 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.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/of_platform.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/spi/spi.h>
#include <linux/fsl_devices.h>
#include <asm/mpc52xx_psc.h>
struct mpc512x_psc_spi {
void (*cs_control)(struct spi_device *spi, bool on);
u32 sysclk;
/* driver internal data */
struct mpc52xx_psc __iomem *psc;
struct mpc512x_psc_fifo __iomem *fifo;
unsigned int irq;
u8 bits_per_word;
u8 busy;
u32 mclk;
u8 eofbyte;
struct workqueue_struct *workqueue;
struct work_struct work;
struct list_head queue;
spinlock_t lock; /* Message queue lock */
struct completion done;
};
/* controller state */
struct mpc512x_psc_spi_cs {
int bits_per_word;
int speed_hz;
};
/* set clock freq, clock ramp, bits per work
* if t is NULL then reset the values to the default values
*/
static int mpc512x_psc_spi_transfer_setup(struct spi_device *spi,
struct spi_transfer *t)
{
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
cs->speed_hz = (t && t->speed_hz)
? t->speed_hz : spi->max_speed_hz;
cs->bits_per_word = (t && t->bits_per_word)
? t->bits_per_word : spi->bits_per_word;
cs->bits_per_word = ((cs->bits_per_word + 7) / 8) * 8;
return 0;
}
static void mpc512x_psc_spi_activate_cs(struct spi_device *spi)
{
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc __iomem *psc = mps->psc;
u32 sicr;
u32 ccr;
u16 bclkdiv;
sicr = in_be32(&psc->sicr);
/* Set clock phase and polarity */
if (spi->mode & SPI_CPHA)
sicr |= 0x00001000;
else
sicr &= ~0x00001000;
if (spi->mode & SPI_CPOL)
sicr |= 0x00002000;
else
sicr &= ~0x00002000;
if (spi->mode & SPI_LSB_FIRST)
sicr |= 0x10000000;
else
sicr &= ~0x10000000;
out_be32(&psc->sicr, sicr);
ccr = in_be32(&psc->ccr);
ccr &= 0xFF000000;
if (cs->speed_hz)
bclkdiv = (mps->mclk / cs->speed_hz) - 1;
else
bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr);
mps->bits_per_word = cs->bits_per_word;
if (mps->cs_control)
mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 1 : 0);
}
static void mpc512x_psc_spi_deactivate_cs(struct spi_device *spi)
{
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
if (mps->cs_control)
mps->cs_control(spi, (spi->mode & SPI_CS_HIGH) ? 0 : 1);
}
/* extract and scale size field in txsz or rxsz */
#define MPC512x_PSC_FIFO_SZ(sz) ((sz & 0x7ff) << 2);
#define EOFBYTE 1
static int mpc512x_psc_spi_transfer_rxtx(struct spi_device *spi,
struct spi_transfer *t)
{
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
size_t len = t->len;
u8 *tx_buf = (u8 *)t->tx_buf;
u8 *rx_buf = (u8 *)t->rx_buf;
if (!tx_buf && !rx_buf && t->len)
return -EINVAL;
/* Zero MR2 */
in_8(&psc->mode);
out_8(&psc->mode, 0x0);
while (len) {
int count;
int i;
u8 data;
size_t fifosz;
int rxcount;
/*
* The number of bytes that can be sent at a time
* depends on the fifo size.
*/
fifosz = MPC512x_PSC_FIFO_SZ(in_be32(&fifo->txsz));
count = min(fifosz, len);
for (i = count; i > 0; i--) {
data = tx_buf ? *tx_buf++ : 0;
if (len == EOFBYTE)
setbits32(&fifo->txcmd, MPC512x_PSC_FIFO_EOF);
out_8(&fifo->txdata_8, data);
len--;
}
INIT_COMPLETION(mps->done);
/* interrupt on tx fifo empty */
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
out_be32(&fifo->tximr, MPC512x_PSC_FIFO_EMPTY);
/* enable transmiter/receiver */
out_8(&psc->command,
MPC52xx_PSC_TX_ENABLE | MPC52xx_PSC_RX_ENABLE);
wait_for_completion(&mps->done);
mdelay(1);
/* rx fifo should have count bytes in it */
rxcount = in_be32(&fifo->rxcnt);
if (rxcount != count)
mdelay(1);
rxcount = in_be32(&fifo->rxcnt);
if (rxcount != count) {
dev_warn(&spi->dev, "expected %d bytes in rx fifo "
"but got %d\n", count, rxcount);
}
rxcount = min(rxcount, count);
for (i = rxcount; i > 0; i--) {
data = in_8(&fifo->rxdata_8);
if (rx_buf)
*rx_buf++ = data;
}
while (in_be32(&fifo->rxcnt)) {
in_8(&fifo->rxdata_8);
}
out_8(&psc->command,
MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
}
/* disable transmiter/receiver and fifo interrupt */
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
out_be32(&fifo->tximr, 0);
return 0;
}
static void mpc512x_psc_spi_work(struct work_struct *work)
{
struct mpc512x_psc_spi *mps = container_of(work,
struct mpc512x_psc_spi,
work);
spin_lock_irq(&mps->lock);
mps->busy = 1;
while (!list_empty(&mps->queue)) {
struct spi_message *m;
struct spi_device *spi;
struct spi_transfer *t = NULL;
unsigned cs_change;
int status;
m = container_of(mps->queue.next, struct spi_message, queue);
list_del_init(&m->queue);
spin_unlock_irq(&mps->lock);
spi = m->spi;
cs_change = 1;
status = 0;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->bits_per_word || t->speed_hz) {
status = mpc512x_psc_spi_transfer_setup(spi, t);
if (status < 0)
break;
}
if (cs_change)
mpc512x_psc_spi_activate_cs(spi);
cs_change = t->cs_change;
status = mpc512x_psc_spi_transfer_rxtx(spi, t);
if (status)
break;
m->actual_length += t->len;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (cs_change)
mpc512x_psc_spi_deactivate_cs(spi);
}
m->status = status;
m->complete(m->context);
if (status || !cs_change)
mpc512x_psc_spi_deactivate_cs(spi);
mpc512x_psc_spi_transfer_setup(spi, NULL);
spin_lock_irq(&mps->lock);
}
mps->busy = 0;
spin_unlock_irq(&mps->lock);
}
static int mpc512x_psc_spi_setup(struct spi_device *spi)
{
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
struct mpc512x_psc_spi_cs *cs = spi->controller_state;
unsigned long flags;
if (spi->bits_per_word % 8)
return -EINVAL;
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
cs->bits_per_word = spi->bits_per_word;
cs->speed_hz = spi->max_speed_hz;
spin_lock_irqsave(&mps->lock, flags);
if (!mps->busy)
mpc512x_psc_spi_deactivate_cs(spi);
spin_unlock_irqrestore(&mps->lock, flags);
return 0;
}
static int mpc512x_psc_spi_transfer(struct spi_device *spi,
struct spi_message *m)
{
struct mpc512x_psc_spi *mps = spi_master_get_devdata(spi->master);
unsigned long flags;
m->actual_length = 0;
m->status = -EINPROGRESS;
spin_lock_irqsave(&mps->lock, flags);
list_add_tail(&m->queue, &mps->queue);
queue_work(mps->workqueue, &mps->work);
spin_unlock_irqrestore(&mps->lock, flags);
return 0;
}
static void mpc512x_psc_spi_cleanup(struct spi_device *spi)
{
kfree(spi->controller_state);
}
static int mpc512x_psc_spi_port_config(struct spi_master *master,
struct mpc512x_psc_spi *mps)
{
struct mpc52xx_psc __iomem *psc = mps->psc;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
struct clk *spiclk;
int ret = 0;
char name[32];
u32 sicr;
u32 ccr;
u16 bclkdiv;
sprintf(name, "psc%d_mclk", master->bus_num);
spiclk = clk_get(&master->dev, name);
clk_enable(spiclk);
mps->mclk = clk_get_rate(spiclk);
clk_put(spiclk);
/* Reset the PSC into a known state */
out_8(&psc->command, MPC52xx_PSC_RST_RX);
out_8(&psc->command, MPC52xx_PSC_RST_TX);
out_8(&psc->command, MPC52xx_PSC_TX_DISABLE | MPC52xx_PSC_RX_DISABLE);
/* Disable psc interrupts all useful interrupts are in fifo */
out_be16(&psc->isr_imr.imr, 0);
/* Disable fifo interrupts, will be enabled later */
out_be32(&fifo->tximr, 0);
out_be32(&fifo->rximr, 0);
/* Setup fifo slice address and size */
/*out_be32(&fifo->txsz, 0x0fe00004);*/
/*out_be32(&fifo->rxsz, 0x0ff00004);*/
sicr = 0x01000000 | /* SIM = 0001 -- 8 bit */
0x00800000 | /* GenClk = 1 -- internal clk */
0x00008000 | /* SPI = 1 */
0x00004000 | /* MSTR = 1 -- SPI master */
0x00000800; /* UseEOF = 1 -- SS low until EOF */
out_be32(&psc->sicr, sicr);
ccr = in_be32(&psc->ccr);
ccr &= 0xFF000000;
bclkdiv = (mps->mclk / 1000000) - 1; /* default 1MHz */
ccr |= (((bclkdiv & 0xff) << 16) | (((bclkdiv >> 8) & 0xff) << 8));
out_be32(&psc->ccr, ccr);
/* Set 2ms DTL delay */
out_8(&psc->ctur, 0x00);
out_8(&psc->ctlr, 0x82);
/* we don't use the alarms */
out_be32(&fifo->rxalarm, 0xfff);
out_be32(&fifo->txalarm, 0);
/* Enable FIFO slices for Rx/Tx */
out_be32(&fifo->rxcmd,
MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
out_be32(&fifo->txcmd,
MPC512x_PSC_FIFO_ENABLE_SLICE | MPC512x_PSC_FIFO_ENABLE_DMA);
mps->bits_per_word = 8;
return ret;
}
static irqreturn_t mpc512x_psc_spi_isr(int irq, void *dev_id)
{
struct mpc512x_psc_spi *mps = (struct mpc512x_psc_spi *)dev_id;
struct mpc512x_psc_fifo __iomem *fifo = mps->fifo;
/* clear interrupt and wake up the work queue */
if (in_be32(&fifo->txisr) &
in_be32(&fifo->tximr) & MPC512x_PSC_FIFO_EMPTY) {
out_be32(&fifo->txisr, MPC512x_PSC_FIFO_EMPTY);
out_be32(&fifo->tximr, 0);
complete(&mps->done);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
/* bus_num is used only for the case dev->platform_data == NULL */
static int __init mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq,
s16 bus_num)
{
struct fsl_spi_platform_data *pdata = dev->platform_data;
struct mpc512x_psc_spi *mps;
struct spi_master *master;
int ret;
void *tempp;
master = spi_alloc_master(dev, sizeof *mps);
if (master == NULL)
return -ENOMEM;
dev_set_drvdata(dev, master);
mps = spi_master_get_devdata(master);
mps->irq = irq;
if (pdata == NULL) {
dev_err(dev, "probe called without platform data, no "
"cs_control function will be called\n");
mps->cs_control = NULL;
mps->sysclk = 0;
master->bus_num = bus_num;
master->num_chipselect = 255;
} else {
mps->cs_control = pdata->cs_control;
mps->sysclk = pdata->sysclk;
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
}
master->setup = mpc512x_psc_spi_setup;
master->transfer = mpc512x_psc_spi_transfer;
master->cleanup = mpc512x_psc_spi_cleanup;
tempp = ioremap(regaddr, size);
if (!tempp) {
dev_err(dev, "could not ioremap I/O port range\n");
ret = -EFAULT;
goto free_master;
}
mps->psc = tempp;
mps->fifo =
(struct mpc512x_psc_fifo *)(tempp + sizeof(struct mpc52xx_psc));
ret = request_irq(mps->irq, mpc512x_psc_spi_isr, IRQF_SHARED,
"mpc512x-psc-spi", mps);
if (ret)
goto free_master;
ret = mpc512x_psc_spi_port_config(master, mps);
if (ret < 0)
goto free_irq;
spin_lock_init(&mps->lock);
init_completion(&mps->done);
INIT_WORK(&mps->work, mpc512x_psc_spi_work);
INIT_LIST_HEAD(&mps->queue);
mps->workqueue =
create_singlethread_workqueue(dev_name(master->dev.parent));
if (mps->workqueue == NULL) {
ret = -EBUSY;
goto free_irq;
}
ret = spi_register_master(master);
if (ret < 0)
goto unreg_master;
return ret;
unreg_master:
destroy_workqueue(mps->workqueue);
free_irq:
free_irq(mps->irq, mps);
free_master:
if (mps->psc)
iounmap(mps->psc);
spi_master_put(master);
return ret;
}
static int __exit mpc512x_psc_spi_do_remove(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
flush_workqueue(mps->workqueue);
destroy_workqueue(mps->workqueue);
spi_unregister_master(master);
free_irq(mps->irq, mps);
if (mps->psc)
iounmap(mps->psc);
return 0;
}
static int __init mpc512x_psc_spi_of_probe(struct of_device *op,
const struct of_device_id *match)
{
const u32 *regaddr_p;
u64 regaddr64, size64;
s16 id = -1;
regaddr_p = of_get_address(op->node, 0, &size64, NULL);
if (!regaddr_p) {
dev_err(&op->dev, "Invalid PSC address\n");
return -EINVAL;
}
regaddr64 = of_translate_address(op->node, regaddr_p);
/* get PSC id (0..11, used by port_config) */
if (op->dev.platform_data == NULL) {
const u32 *psc_nump;
psc_nump = of_get_property(op->node, "cell-index", NULL);
if (!psc_nump || *psc_nump > 11) {
dev_err(&op->dev, "mpc512x_psc_spi: Device node %s "
"has invalid cell-index property\n",
op->node->full_name);
return -EINVAL;
}
id = *psc_nump;
}
return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64,
irq_of_parse_and_map(op->node, 0), id);
}
static int __exit mpc512x_psc_spi_of_remove(struct of_device *op)
{
return mpc512x_psc_spi_do_remove(&op->dev);
}
static struct of_device_id mpc512x_psc_spi_of_match[] = {
{ .compatible = "fsl,mpc5121-psc-spi", },
{},
};
MODULE_DEVICE_TABLE(of, mpc512x_psc_spi_of_match);
static struct of_platform_driver mpc512x_psc_spi_of_driver = {
.match_table = mpc512x_psc_spi_of_match,
.probe = mpc512x_psc_spi_of_probe,
.remove = __exit_p(mpc512x_psc_spi_of_remove),
.driver = {
.name = "mpc512x-psc-spi",
.owner = THIS_MODULE,
},
};
static int __init mpc512x_psc_spi_init(void)
{
return of_register_platform_driver(&mpc512x_psc_spi_of_driver);
}
module_init(mpc512x_psc_spi_init);
static void __exit mpc512x_psc_spi_exit(void)
{
of_unregister_platform_driver(&mpc512x_psc_spi_of_driver);
}
module_exit(mpc512x_psc_spi_exit);
MODULE_AUTHOR("John Rigby");
MODULE_DESCRIPTION("MPC512x PSC SPI Driver");
MODULE_LICENSE("GPL");
...@@ -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,6 +843,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) ...@@ -765,6 +843,9 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
kfree(spi->controller_state); kfree(spi->controller_state);
} }
if (spi->chip_select < spi->master->num_chipselect) {
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
if (mcspi_dma->dma_rx_channel != -1) { if (mcspi_dma->dma_rx_channel != -1) {
omap_free_dma(mcspi_dma->dma_rx_channel); omap_free_dma(mcspi_dma->dma_rx_channel);
mcspi_dma->dma_rx_channel = -1; mcspi_dma->dma_rx_channel = -1;
...@@ -773,6 +854,7 @@ static void omap2_mcspi_cleanup(struct spi_device *spi) ...@@ -773,6 +854,7 @@ static void omap2_mcspi_cleanup(struct spi_device *spi)
omap_free_dma(mcspi_dma->dma_tx_channel); omap_free_dma(mcspi_dma->dma_tx_channel);
mcspi_dma->dma_tx_channel = -1; mcspi_dma->dma_tx_channel = -1;
} }
}
} }
static void omap2_mcspi_work(struct work_struct *work) static void omap2_mcspi_work(struct work_struct *work)
...@@ -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) {
...@@ -347,12 +322,75 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) ...@@ -347,12 +322,75 @@ int mpc8xxx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
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