Commit 021db8e2 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: (77 commits)
  spi/omap: Fix DMA API usage in OMAP MCSPI driver
  spi/imx: correct the test on platform_get_irq() return value
  spi/topcliff: Typo fix threhold to threshold
  spi/dw_spi Typo change diable to disable.
  spi/fsl_espi: change the read behaviour of the SPIRF
  spi/mpc52xx-psc-spi: move probe/remove to proper sections
  spi/dw_spi: add DMA support
  spi/dw_spi: change to EXPORT_SYMBOL_GPL for exported APIs
  spi/dw_spi: Fix too short timeout in spi polling loop
  spi/pl022: convert running variable
  spi/pl022: convert busy flag to a bool
  spi/pl022: pass the returned sglen to the DMA engine
  spi/pl022: map the buffers on the DMA engine
  spi/topcliff_pch: Fix data transfer issue
  spi/imx: remove autodetection
  spi/pxa2xx: pass of_node to spi device and set a parent device
  spi/pxa2xx: Modify RX-Tresh instead of busy-loop for the remaining RX bytes.
  spi/pxa2xx: Add chipselect support for Sodaville
  spi/pxa2xx: Consider CE4100's FIFO depth
  spi/pxa2xx: Add CE4100 support
  ...
parents 72eb6a79 07fe0351
...@@ -19,7 +19,7 @@ Declaring PXA2xx Master Controllers ...@@ -19,7 +19,7 @@ Declaring PXA2xx Master Controllers
----------------------------------- -----------------------------------
Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
"platform device". The master configuration is passed to the driver via a table "platform device". The master configuration is passed to the driver via a table
found in arch/arm/mach-pxa/include/mach/pxa2xx_spi.h: found in include/linux/spi/pxa2xx_spi.h:
struct pxa2xx_spi_master { struct pxa2xx_spi_master {
enum pxa_ssp_type ssp_type; enum pxa_ssp_type ssp_type;
...@@ -94,7 +94,7 @@ using the "spi_board_info" structure found in "linux/spi/spi.h". See ...@@ -94,7 +94,7 @@ using the "spi_board_info" structure found in "linux/spi/spi.h". See
Each slave device attached to the PXA must provide slave specific configuration Each slave device attached to the PXA must provide slave specific configuration
information via the structure "pxa2xx_spi_chip" found in information via the structure "pxa2xx_spi_chip" found in
"arch/arm/mach-pxa/include/mach/pxa2xx_spi.h". The pxa2xx_spi master controller driver "include/linux/spi/pxa2xx_spi.h". The pxa2xx_spi master controller driver
will uses the configuration whenever the driver communicates with the slave will uses the configuration whenever the driver communicates with the slave
device. All fields are optional. device. All fields are optional.
......
...@@ -412,12 +412,7 @@ static struct resource dm355_spi0_resources[] = { ...@@ -412,12 +412,7 @@ static struct resource dm355_spi0_resources[] = {
static struct davinci_spi_platform_data dm355_spi0_pdata = { static struct davinci_spi_platform_data dm355_spi0_pdata = {
.version = SPI_VERSION_1, .version = SPI_VERSION_1,
.num_chipselect = 2, .num_chipselect = 2,
.clk_internal = 1, .cshold_bug = true,
.cs_hold = 1,
.intr_level = 0,
.poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */
.c2tdelay = 0,
.t2cdelay = 0,
}; };
static struct platform_device dm355_spi0_device = { static struct platform_device dm355_spi0_device = {
.name = "spi_davinci", .name = "spi_davinci",
......
...@@ -625,12 +625,6 @@ static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32); ...@@ -625,12 +625,6 @@ static u64 dm365_spi0_dma_mask = DMA_BIT_MASK(32);
static struct davinci_spi_platform_data dm365_spi0_pdata = { static struct davinci_spi_platform_data dm365_spi0_pdata = {
.version = SPI_VERSION_1, .version = SPI_VERSION_1,
.num_chipselect = 2, .num_chipselect = 2,
.clk_internal = 1,
.cs_hold = 1,
.intr_level = 0,
.poll_mode = 1, /* 0 -> interrupt mode 1-> polling mode */
.c2tdelay = 0,
.t2cdelay = 0,
}; };
static struct resource dm365_spi0_resources[] = { static struct resource dm365_spi0_resources[] = {
......
...@@ -19,26 +19,66 @@ ...@@ -19,26 +19,66 @@
#ifndef __ARCH_ARM_DAVINCI_SPI_H #ifndef __ARCH_ARM_DAVINCI_SPI_H
#define __ARCH_ARM_DAVINCI_SPI_H #define __ARCH_ARM_DAVINCI_SPI_H
#define SPI_INTERN_CS 0xFF
enum { enum {
SPI_VERSION_1, /* For DM355/DM365/DM6467 */ SPI_VERSION_1, /* For DM355/DM365/DM6467 */
SPI_VERSION_2, /* For DA8xx */ SPI_VERSION_2, /* For DA8xx */
}; };
/**
* davinci_spi_platform_data - Platform data for SPI master device on DaVinci
*
* @version: version of the SPI IP. Different DaVinci devices have slightly
* varying versions of the same IP.
* @num_chipselect: number of chipselects supported by this SPI master
* @intr_line: interrupt line used to connect the SPI IP to the ARM interrupt
* controller withn the SoC. Possible values are 0 and 1.
* @chip_sel: list of GPIOs which can act as chip-selects for the SPI.
* SPI_INTERN_CS denotes internal SPI chip-select. Not necessary
* to populate if all chip-selects are internal.
* @cshold_bug: set this to true if the SPI controller on your chip requires
* a write to CSHOLD bit in between transfers (like in DM355).
*/
struct davinci_spi_platform_data { struct davinci_spi_platform_data {
u8 version; u8 version;
u8 num_chipselect; u8 num_chipselect;
u8 intr_line;
u8 *chip_sel;
bool cshold_bug;
};
/**
* davinci_spi_config - Per-chip-select configuration for SPI slave devices
*
* @wdelay: amount of delay between transmissions. Measured in number of
* SPI module clocks.
* @odd_parity: polarity of parity flag at the end of transmit data stream.
* 0 - odd parity, 1 - even parity.
* @parity_enable: enable transmission of parity at end of each transmit
* data stream.
* @io_type: type of IO transfer. Choose between polled, interrupt and DMA.
* @timer_disable: disable chip-select timers (setup and hold)
* @c2tdelay: chip-select setup time. Measured in number of SPI module clocks.
* @t2cdelay: chip-select hold time. Measured in number of SPI module clocks.
* @t2edelay: transmit data finished to SPI ENAn pin inactive time. Measured
* in number of SPI clocks.
* @c2edelay: chip-select active to SPI ENAn signal active time. Measured in
* number of SPI clocks.
*/
struct davinci_spi_config {
u8 wdelay; u8 wdelay;
u8 odd_parity; u8 odd_parity;
u8 parity_enable; u8 parity_enable;
u8 wait_enable; #define SPI_IO_TYPE_INTR 0
#define SPI_IO_TYPE_POLL 1
#define SPI_IO_TYPE_DMA 2
u8 io_type;
u8 timer_disable; u8 timer_disable;
u8 clk_internal;
u8 cs_hold;
u8 intr_level;
u8 poll_mode;
u8 use_dma;
u8 c2tdelay; u8 c2tdelay;
u8 t2cdelay; u8 t2cdelay;
u8 t2edelay;
u8 c2edelay;
}; };
#endif /* __ARCH_ARM_DAVINCI_SPI_H */ #endif /* __ARCH_ARM_DAVINCI_SPI_H */
...@@ -17,13 +17,13 @@ ...@@ -17,13 +17,13 @@
#include <linux/mtd/nand-gpio.h> #include <linux/mtd/nand-gpio.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <mach/pxa25x.h> #include <mach/pxa25x.h>
#include <mach/pxa2xx_spi.h>
#include "generic.h" #include "generic.h"
......
...@@ -19,12 +19,12 @@ ...@@ -19,12 +19,12 @@
#include <video/mbxfb.h> #include <video/mbxfb.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/libertas_spi.h> #include <linux/spi/libertas_spi.h>
#include <mach/pxa27x.h> #include <mach/pxa27x.h>
#include <mach/ohci.h> #include <mach/ohci.h>
#include <mach/mmc.h> #include <mach/mmc.h>
#include <mach/pxa2xx_spi.h>
#include "generic.h" #include "generic.h"
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <linux/spi/corgi_lcd.h> #include <linux/spi/corgi_lcd.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mtd/sharpsl.h> #include <linux/mtd/sharpsl.h>
#include <linux/input/matrix_keypad.h> #include <linux/input/matrix_keypad.h>
#include <video/w100fb.h> #include <video/w100fb.h>
...@@ -48,7 +49,6 @@ ...@@ -48,7 +49,6 @@
#include <mach/irda.h> #include <mach/irda.h>
#include <mach/mmc.h> #include <mach/mmc.h>
#include <mach/udc.h> #include <mach/udc.h>
#include <mach/pxa2xx_spi.h>
#include <mach/corgi.h> #include <mach/corgi.h>
#include <mach/sharpsl_pm.h> #include <mach/sharpsl_pm.h>
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/spi/pxa2xx_spi.h>
#include <asm/pmu.h> #include <asm/pmu.h>
#include <mach/udc.h> #include <mach/udc.h>
...@@ -12,7 +13,6 @@ ...@@ -12,7 +13,6 @@
#include <mach/irda.h> #include <mach/irda.h>
#include <mach/ohci.h> #include <mach/ohci.h>
#include <plat/pxa27x_keypad.h> #include <plat/pxa27x_keypad.h>
#include <mach/pxa2xx_spi.h>
#include <mach/camera.h> #include <mach/camera.h>
#include <mach/audio.h> #include <mach/audio.h>
#include <mach/hardware.h> #include <mach/hardware.h>
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/tdo24m.h> #include <linux/spi/tdo24m.h>
#include <linux/spi/libertas_spi.h> #include <linux/spi/libertas_spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
#include <linux/apm-emulation.h> #include <linux/apm-emulation.h>
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -46,7 +47,6 @@ ...@@ -46,7 +47,6 @@
#include <plat/pxa27x_keypad.h> #include <plat/pxa27x_keypad.h>
#include <plat/i2c.h> #include <plat/i2c.h>
#include <mach/camera.h> #include <mach/camera.h>
#include <mach/pxa2xx_spi.h>
#include "generic.h" #include "generic.h"
#include "devices.h" #include "devices.h"
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <linux/regulator/max1586.h> #include <linux/regulator/max1586.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/usb/gpio_vbus.h> #include <linux/usb/gpio_vbus.h>
#include <mach/hardware.h> #include <mach/hardware.h>
...@@ -43,7 +44,6 @@ ...@@ -43,7 +44,6 @@
#include <mach/hx4700.h> #include <mach/hx4700.h>
#include <plat/i2c.h> #include <plat/i2c.h>
#include <mach/irda.h> #include <mach/irda.h>
#include <mach/pxa2xx_spi.h>
#include <video/platform_lcd.h> #include <video/platform_lcd.h>
#include <video/w100fb.h> #include <video/w100fb.h>
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <mach/mxm8x10.h> #include <mach/mxm8x10.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <mach/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/can/platform/mcp251x.h> #include <linux/can/platform/mcp251x.h>
#include "generic.h" #include "generic.h"
......
/*
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef PXA2XX_SPI_H_
#define PXA2XX_SPI_H_
#define PXA2XX_CS_ASSERT (0x01)
#define PXA2XX_CS_DEASSERT (0x02)
/* device.platform_data for SSP controller devices */
struct pxa2xx_spi_master {
u32 clock_enable;
u16 num_chipselect;
u8 enable_dma;
};
/* spi_board_info.controller_data for SPI slave devices,
* copied to spi_device.platform_data ... mostly for dma tuning
*/
struct pxa2xx_spi_chip {
u8 tx_threshold;
u8 rx_threshold;
u8 dma_burst_size;
u32 timeout;
u8 enable_loopback;
int gpio_cs;
void (*cs_control)(u32 command);
};
extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
#endif /*PXA2XX_SPI_H_*/
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/smc91x.h> #include <linux/smc91x.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/leds.h> #include <linux/leds.h>
...@@ -42,7 +43,6 @@ ...@@ -42,7 +43,6 @@
#include <mach/pxa300.h> #include <mach/pxa300.h>
#include <mach/pxafb.h> #include <mach/pxafb.h>
#include <mach/mmc.h> #include <mach/mmc.h>
#include <mach/pxa2xx_spi.h>
#include <plat/pxa27x_keypad.h> #include <plat/pxa27x_keypad.h>
#include <mach/littleton.h> #include <mach/littleton.h>
#include <plat/i2c.h> #include <plat/i2c.h>
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <mach/pxa2xx_spi.h> #include <linux/spi/pxa2xx_spi.h>
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/memory.h> #include <asm/memory.h>
......
...@@ -25,12 +25,12 @@ ...@@ -25,12 +25,12 @@
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/max7301.h> #include <linux/spi/max7301.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <mach/pxa27x.h> #include <mach/pxa27x.h>
#include <mach/pxa2xx_spi.h>
#include <mach/pcm027.h> #include <mach/pcm027.h>
#include "generic.h" #include "generic.h"
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mtd/sharpsl.h> #include <linux/mtd/sharpsl.h>
#include <mach/hardware.h> #include <mach/hardware.h>
...@@ -43,7 +44,6 @@ ...@@ -43,7 +44,6 @@
#include <mach/irda.h> #include <mach/irda.h>
#include <mach/poodle.h> #include <mach/poodle.h>
#include <mach/pxafb.h> #include <mach/pxafb.h>
#include <mach/pxa2xx_spi.h>
#include <plat/i2c.h> #include <plat/i2c.h>
#include <asm/hardware/scoop.h> #include <asm/hardware/scoop.h>
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <linux/spi/corgi_lcd.h> #include <linux/spi/corgi_lcd.h>
#include <linux/mtd/physmap.h> #include <linux/spi/pxa2xx_spi.h>
#include <linux/mtd/sharpsl.h> #include <linux/mtd/sharpsl.h>
#include <linux/input/matrix_keypad.h> #include <linux/input/matrix_keypad.h>
#include <linux/regulator/machine.h> #include <linux/regulator/machine.h>
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include <mach/mmc.h> #include <mach/mmc.h>
#include <mach/ohci.h> #include <mach/ohci.h>
#include <mach/pxafb.h> #include <mach/pxafb.h>
#include <mach/pxa2xx_spi.h>
#include <mach/spitz.h> #include <mach/spitz.h>
#include <mach/sharpsl_pm.h> #include <mach/sharpsl_pm.h>
#include <mach/smemc.h> #include <mach/smemc.h>
......
...@@ -46,11 +46,11 @@ ...@@ -46,11 +46,11 @@
#include <plat/i2c.h> #include <plat/i2c.h>
#include <mach/mmc.h> #include <mach/mmc.h>
#include <mach/udc.h> #include <mach/udc.h>
#include <mach/pxa2xx_spi.h>
#include <mach/pxa27x-udc.h> #include <mach/pxa27x-udc.h>
#include <mach/smemc.h> #include <mach/smemc.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mfd/da903x.h> #include <linux/mfd/da903x.h>
#include <linux/sht15.h> #include <linux/sht15.h>
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/pda_power.h> #include <linux/pda_power.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/input/matrix_keypad.h> #include <linux/input/matrix_keypad.h>
#include <asm/setup.h> #include <asm/setup.h>
...@@ -44,7 +45,6 @@ ...@@ -44,7 +45,6 @@
#include <mach/mmc.h> #include <mach/mmc.h>
#include <mach/udc.h> #include <mach/udc.h>
#include <mach/tosa_bt.h> #include <mach/tosa_bt.h>
#include <mach/pxa2xx_spi.h>
#include <mach/audio.h> #include <mach/audio.h>
#include <mach/smemc.h> #include <mach/smemc.h>
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <asm/mach/flash.h> #include <asm/mach/flash.h>
#include <mach/pxa27x.h> #include <mach/pxa27x.h>
#include <mach/pxa2xx_spi.h>
#include <mach/trizeps4.h> #include <mach/trizeps4.h>
#include <mach/audio.h> #include <mach/audio.h>
#include <mach/pxafb.h> #include <mach/pxafb.h>
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/z2_battery.h> #include <linux/z2_battery.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/spi/libertas_spi.h> #include <linux/spi/libertas_spi.h>
#include <linux/spi/lms283gf05.h> #include <linux/spi/lms283gf05.h>
#include <linux/power_supply.h> #include <linux/power_supply.h>
...@@ -38,7 +39,6 @@ ...@@ -38,7 +39,6 @@
#include <mach/pxafb.h> #include <mach/pxafb.h>
#include <mach/mmc.h> #include <mach/mmc.h>
#include <plat/pxa27x_keypad.h> #include <plat/pxa27x_keypad.h>
#include <mach/pxa2xx_spi.h>
#include <plat/i2c.h> #include <plat/i2c.h>
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/dm9000.h> #include <linux/dm9000.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/mtd/mtd.h> #include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h> #include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
...@@ -41,7 +42,6 @@ ...@@ -41,7 +42,6 @@
#include <mach/pxa27x-udc.h> #include <mach/pxa27x-udc.h>
#include <mach/udc.h> #include <mach/udc.h>
#include <mach/pxafb.h> #include <mach/pxafb.h>
#include <mach/pxa2xx_spi.h>
#include <mach/mfp-pxa27x.h> #include <mach/mfp-pxa27x.h>
#include <mach/pm.h> #include <mach/pm.h>
#include <mach/audio.h> #include <mach/audio.h>
......
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/io.h> #include <linux/io.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <plat/ssp.h>
static DEFINE_MUTEX(ssp_lock); static DEFINE_MUTEX(ssp_lock);
static LIST_HEAD(ssp_list); static LIST_HEAD(ssp_list);
......
...@@ -111,11 +111,14 @@ config SPI_COLDFIRE_QSPI ...@@ -111,11 +111,14 @@ config SPI_COLDFIRE_QSPI
will be called coldfire_qspi. will be called coldfire_qspi.
config SPI_DAVINCI config SPI_DAVINCI
tristate "SPI controller driver for DaVinci/DA8xx SoC's" tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
depends on SPI_MASTER && ARCH_DAVINCI depends on SPI_MASTER && ARCH_DAVINCI
select SPI_BITBANG select SPI_BITBANG
help help
SPI master controller for DaVinci and DA8xx SPI modules. SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
This driver can also be built as a module. The module will be called
davinci_spi.
config SPI_EP93XX config SPI_EP93XX
tristate "Cirrus Logic EP93xx SPI controller" tristate "Cirrus Logic EP93xx SPI controller"
...@@ -267,12 +270,15 @@ config SPI_PPC4xx ...@@ -267,12 +270,15 @@ config SPI_PPC4xx
config SPI_PXA2XX config SPI_PXA2XX
tristate "PXA2xx SSP SPI master" tristate "PXA2xx SSP SPI master"
depends on ARCH_PXA && EXPERIMENTAL depends on (ARCH_PXA || (X86_32 && PCI)) && EXPERIMENTAL
select PXA_SSP select PXA_SSP if ARCH_PXA
help help
This enables using a PXA2xx SSP port as a SPI master controller. This enables using a PXA2xx or Sodaville SSP port as a SPI master
The driver can be configured to use any SSP port and additional controller. The driver can be configured to use any SSP port and
documentation can be found a Documentation/spi/pxa2xx. additional documentation can be found a Documentation/spi/pxa2xx.
config SPI_PXA2XX_PCI
def_bool SPI_PXA2XX && X86_32 && PCI
config SPI_S3C24XX config SPI_S3C24XX
tristate "Samsung S3C24XX series SPI" tristate "Samsung S3C24XX series SPI"
...@@ -353,7 +359,6 @@ config SPI_XILINX ...@@ -353,7 +359,6 @@ config SPI_XILINX
tristate "Xilinx SPI controller common module" tristate "Xilinx SPI controller common module"
depends on HAS_IOMEM && EXPERIMENTAL depends on HAS_IOMEM && EXPERIMENTAL
select SPI_BITBANG select SPI_BITBANG
select SPI_XILINX_OF if (XILINX_VIRTEX || MICROBLAZE)
help help
This exposes the SPI controller IP from the Xilinx EDK. This exposes the SPI controller IP from the Xilinx EDK.
...@@ -362,19 +367,6 @@ config SPI_XILINX ...@@ -362,19 +367,6 @@ config SPI_XILINX
Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)"
config SPI_XILINX_OF
tristate "Xilinx SPI controller OF device"
depends on SPI_XILINX && (XILINX_VIRTEX || MICROBLAZE)
help
This is the OF driver for the SPI controller IP from the Xilinx EDK.
config SPI_XILINX_PLTFM
tristate "Xilinx SPI controller platform device"
depends on SPI_XILINX
help
This is the platform driver for the SPI controller IP
from the Xilinx EDK.
config SPI_NUC900 config SPI_NUC900
tristate "Nuvoton NUC900 series SPI" tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900 && EXPERIMENTAL depends on ARCH_W90X900 && EXPERIMENTAL
...@@ -396,6 +388,10 @@ config SPI_DW_PCI ...@@ -396,6 +388,10 @@ config SPI_DW_PCI
tristate "PCI interface driver for DW SPI core" tristate "PCI interface driver for DW SPI core"
depends on SPI_DESIGNWARE && PCI depends on SPI_DESIGNWARE && PCI
config SPI_DW_MID_DMA
bool "DMA support for DW SPI controller on Intel Moorestown platform"
depends on SPI_DW_PCI && INTEL_MID_DMAC
config SPI_DW_MMIO config SPI_DW_MMIO
tristate "Memory-mapped io interface driver for DW SPI core" tristate "Memory-mapped io interface driver for DW SPI core"
depends on SPI_DESIGNWARE && HAVE_CLK depends on SPI_DESIGNWARE && HAVE_CLK
......
...@@ -17,13 +17,15 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o ...@@ -17,13 +17,15 @@ obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o
obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o 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_midpci.o
dw_spi_midpci-objs := dw_spi_pci.o dw_spi_mid.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_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
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += pxa2xx_spi_pci.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o 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
...@@ -43,8 +45,6 @@ obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o ...@@ -43,8 +45,6 @@ obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_XILINX_OF) += xilinx_spi_of.o
obj-$(CONFIG_SPI_XILINX_PLTFM) += xilinx_spi_pltfm.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
......
...@@ -252,11 +252,6 @@ ...@@ -252,11 +252,6 @@
#define STATE_DONE ((void *) 2) #define STATE_DONE ((void *) 2)
#define STATE_ERROR ((void *) -1) #define STATE_ERROR ((void *) -1)
/*
* Queue State
*/
#define QUEUE_RUNNING (0)
#define QUEUE_STOPPED (1)
/* /*
* SSP State - Whether Enabled or Disabled * SSP State - Whether Enabled or Disabled
*/ */
...@@ -344,7 +339,7 @@ struct vendor_data { ...@@ -344,7 +339,7 @@ struct vendor_data {
* @lock: spinlock to syncronise access to driver data * @lock: spinlock to syncronise access to driver data
* @workqueue: a workqueue on which any spi_message request is queued * @workqueue: a workqueue on which any spi_message request is queued
* @busy: workqueue is busy * @busy: workqueue is busy
* @run: workqueue is running * @running: workqueue is running
* @pump_transfers: Tasklet used in Interrupt Transfer mode * @pump_transfers: Tasklet used in Interrupt Transfer mode
* @cur_msg: Pointer to current spi_message being processed * @cur_msg: Pointer to current spi_message being processed
* @cur_transfer: Pointer to current spi_transfer * @cur_transfer: Pointer to current spi_transfer
...@@ -369,8 +364,8 @@ struct pl022 { ...@@ -369,8 +364,8 @@ struct pl022 {
struct work_struct pump_messages; struct work_struct pump_messages;
spinlock_t queue_lock; spinlock_t queue_lock;
struct list_head queue; struct list_head queue;
int busy; bool busy;
int run; bool running;
/* Message transfer pump */ /* Message transfer pump */
struct tasklet_struct pump_transfers; struct tasklet_struct pump_transfers;
struct spi_message *cur_msg; struct spi_message *cur_msg;
...@@ -782,9 +777,9 @@ static void *next_transfer(struct pl022 *pl022) ...@@ -782,9 +777,9 @@ static void *next_transfer(struct pl022 *pl022)
static void unmap_free_dma_scatter(struct pl022 *pl022) static void unmap_free_dma_scatter(struct pl022 *pl022)
{ {
/* Unmap and free the SG tables */ /* Unmap and free the SG tables */
dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl, dma_unmap_sg(pl022->dma_tx_channel->device->dev, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, DMA_TO_DEVICE); pl022->sgt_tx.nents, DMA_TO_DEVICE);
dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl, dma_unmap_sg(pl022->dma_rx_channel->device->dev, pl022->sgt_rx.sgl,
pl022->sgt_rx.nents, DMA_FROM_DEVICE); pl022->sgt_rx.nents, DMA_FROM_DEVICE);
sg_free_table(&pl022->sgt_rx); sg_free_table(&pl022->sgt_rx);
sg_free_table(&pl022->sgt_tx); sg_free_table(&pl022->sgt_tx);
...@@ -917,7 +912,7 @@ static int configure_dma(struct pl022 *pl022) ...@@ -917,7 +912,7 @@ static int configure_dma(struct pl022 *pl022)
}; };
unsigned int pages; unsigned int pages;
int ret; int ret;
int sglen; int rx_sglen, tx_sglen;
struct dma_chan *rxchan = pl022->dma_rx_channel; struct dma_chan *rxchan = pl022->dma_rx_channel;
struct dma_chan *txchan = pl022->dma_tx_channel; struct dma_chan *txchan = pl022->dma_tx_channel;
struct dma_async_tx_descriptor *rxdesc; struct dma_async_tx_descriptor *rxdesc;
...@@ -956,7 +951,7 @@ static int configure_dma(struct pl022 *pl022) ...@@ -956,7 +951,7 @@ static int configure_dma(struct pl022 *pl022)
tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
break; break;
case WRITING_U32: case WRITING_U32:
tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;; tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
break; break;
} }
...@@ -991,20 +986,20 @@ static int configure_dma(struct pl022 *pl022) ...@@ -991,20 +986,20 @@ static int configure_dma(struct pl022 *pl022)
pl022->cur_transfer->len, &pl022->sgt_tx); pl022->cur_transfer->len, &pl022->sgt_tx);
/* Map DMA buffers */ /* Map DMA buffers */
sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_rx.sgl, rx_sglen = dma_map_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
pl022->sgt_rx.nents, DMA_FROM_DEVICE); pl022->sgt_rx.nents, DMA_FROM_DEVICE);
if (!sglen) if (!rx_sglen)
goto err_rx_sgmap; goto err_rx_sgmap;
sglen = dma_map_sg(&pl022->adev->dev, pl022->sgt_tx.sgl, tx_sglen = dma_map_sg(txchan->device->dev, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, DMA_TO_DEVICE); pl022->sgt_tx.nents, DMA_TO_DEVICE);
if (!sglen) if (!tx_sglen)
goto err_tx_sgmap; goto err_tx_sgmap;
/* Send both scatterlists */ /* Send both scatterlists */
rxdesc = rxchan->device->device_prep_slave_sg(rxchan, rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
pl022->sgt_rx.sgl, pl022->sgt_rx.sgl,
pl022->sgt_rx.nents, rx_sglen,
DMA_FROM_DEVICE, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!rxdesc) if (!rxdesc)
...@@ -1012,7 +1007,7 @@ static int configure_dma(struct pl022 *pl022) ...@@ -1012,7 +1007,7 @@ static int configure_dma(struct pl022 *pl022)
txdesc = txchan->device->device_prep_slave_sg(txchan, txdesc = txchan->device->device_prep_slave_sg(txchan,
pl022->sgt_tx.sgl, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, tx_sglen,
DMA_TO_DEVICE, DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK); DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!txdesc) if (!txdesc)
...@@ -1040,10 +1035,10 @@ static int configure_dma(struct pl022 *pl022) ...@@ -1040,10 +1035,10 @@ static int configure_dma(struct pl022 *pl022)
txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0); txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
err_rxdesc: err_rxdesc:
rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0); rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl, dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, DMA_TO_DEVICE); pl022->sgt_tx.nents, DMA_TO_DEVICE);
err_tx_sgmap: err_tx_sgmap:
dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl, dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl,
pl022->sgt_tx.nents, DMA_FROM_DEVICE); pl022->sgt_tx.nents, DMA_FROM_DEVICE);
err_rx_sgmap: err_rx_sgmap:
sg_free_table(&pl022->sgt_tx); sg_free_table(&pl022->sgt_tx);
...@@ -1460,8 +1455,8 @@ static void pump_messages(struct work_struct *work) ...@@ -1460,8 +1455,8 @@ static void pump_messages(struct work_struct *work)
/* Lock queue and check for queue work */ /* Lock queue and check for queue work */
spin_lock_irqsave(&pl022->queue_lock, flags); spin_lock_irqsave(&pl022->queue_lock, flags);
if (list_empty(&pl022->queue) || pl022->run == QUEUE_STOPPED) { if (list_empty(&pl022->queue) || !pl022->running) {
pl022->busy = 0; pl022->busy = false;
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
return; return;
} }
...@@ -1475,7 +1470,7 @@ static void pump_messages(struct work_struct *work) ...@@ -1475,7 +1470,7 @@ static void pump_messages(struct work_struct *work)
list_entry(pl022->queue.next, struct spi_message, queue); list_entry(pl022->queue.next, struct spi_message, queue);
list_del_init(&pl022->cur_msg->queue); list_del_init(&pl022->cur_msg->queue);
pl022->busy = 1; pl022->busy = true;
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
/* Initial message state */ /* Initial message state */
...@@ -1507,8 +1502,8 @@ static int __init init_queue(struct pl022 *pl022) ...@@ -1507,8 +1502,8 @@ static int __init init_queue(struct pl022 *pl022)
INIT_LIST_HEAD(&pl022->queue); INIT_LIST_HEAD(&pl022->queue);
spin_lock_init(&pl022->queue_lock); spin_lock_init(&pl022->queue_lock);
pl022->run = QUEUE_STOPPED; pl022->running = false;
pl022->busy = 0; pl022->busy = false;
tasklet_init(&pl022->pump_transfers, tasklet_init(&pl022->pump_transfers,
pump_transfers, (unsigned long)pl022); pump_transfers, (unsigned long)pl022);
...@@ -1529,12 +1524,12 @@ static int start_queue(struct pl022 *pl022) ...@@ -1529,12 +1524,12 @@ static int start_queue(struct pl022 *pl022)
spin_lock_irqsave(&pl022->queue_lock, flags); spin_lock_irqsave(&pl022->queue_lock, flags);
if (pl022->run == QUEUE_RUNNING || pl022->busy) { if (pl022->running || pl022->busy) {
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
return -EBUSY; return -EBUSY;
} }
pl022->run = QUEUE_RUNNING; pl022->running = true;
pl022->cur_msg = NULL; pl022->cur_msg = NULL;
pl022->cur_transfer = NULL; pl022->cur_transfer = NULL;
pl022->cur_chip = NULL; pl022->cur_chip = NULL;
...@@ -1566,7 +1561,8 @@ static int stop_queue(struct pl022 *pl022) ...@@ -1566,7 +1561,8 @@ 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; else
pl022->running = false;
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
...@@ -1684,7 +1680,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg) ...@@ -1684,7 +1680,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
spin_lock_irqsave(&pl022->queue_lock, flags); spin_lock_irqsave(&pl022->queue_lock, flags);
if (pl022->run == QUEUE_STOPPED) { if (!pl022->running) {
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
return -ESHUTDOWN; return -ESHUTDOWN;
} }
...@@ -1693,7 +1689,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg) ...@@ -1693,7 +1689,7 @@ static int pl022_transfer(struct spi_device *spi, struct spi_message *msg)
msg->state = STATE_START; msg->state = STATE_START;
list_add_tail(&msg->queue, &pl022->queue); list_add_tail(&msg->queue, &pl022->queue);
if (pl022->run == QUEUE_RUNNING && !pl022->busy) if (pl022->running && !pl022->busy)
queue_work(pl022->workqueue, &pl022->pump_messages); queue_work(pl022->workqueue, &pl022->pump_messages);
spin_unlock_irqrestore(&pl022->queue_lock, flags); spin_unlock_irqrestore(&pl022->queue_lock, flags);
......
/* /*
* Copyright (C) 2009 Texas Instruments. * Copyright (C) 2009 Texas Instruments.
* Copyright (C) 2010 EF Johnson Technologies
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -38,11 +39,6 @@ ...@@ -38,11 +39,6 @@
#define CS_DEFAULT 0xFF #define CS_DEFAULT 0xFF
#define SPI_BUFSIZ (SMP_CACHE_BYTES + 1)
#define DAVINCI_DMA_DATA_TYPE_S8 0x01
#define DAVINCI_DMA_DATA_TYPE_S16 0x02
#define DAVINCI_DMA_DATA_TYPE_S32 0x04
#define SPIFMT_PHASE_MASK BIT(16) #define SPIFMT_PHASE_MASK BIT(16)
#define SPIFMT_POLARITY_MASK BIT(17) #define SPIFMT_POLARITY_MASK BIT(17)
#define SPIFMT_DISTIMER_MASK BIT(18) #define SPIFMT_DISTIMER_MASK BIT(18)
...@@ -52,34 +48,43 @@ ...@@ -52,34 +48,43 @@
#define SPIFMT_ODD_PARITY_MASK BIT(23) #define SPIFMT_ODD_PARITY_MASK BIT(23)
#define SPIFMT_WDELAY_MASK 0x3f000000u #define SPIFMT_WDELAY_MASK 0x3f000000u
#define SPIFMT_WDELAY_SHIFT 24 #define SPIFMT_WDELAY_SHIFT 24
#define SPIFMT_CHARLEN_MASK 0x0000001Fu #define SPIFMT_PRESCALE_SHIFT 8
/* SPIGCR1 */
#define SPIGCR1_SPIENA_MASK 0x01000000u
/* SPIPC0 */ /* SPIPC0 */
#define SPIPC0_DIFUN_MASK BIT(11) /* MISO */ #define SPIPC0_DIFUN_MASK BIT(11) /* MISO */
#define SPIPC0_DOFUN_MASK BIT(10) /* MOSI */ #define SPIPC0_DOFUN_MASK BIT(10) /* MOSI */
#define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */ #define SPIPC0_CLKFUN_MASK BIT(9) /* CLK */
#define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */ #define SPIPC0_SPIENA_MASK BIT(8) /* nREADY */
#define SPIPC0_EN1FUN_MASK BIT(1)
#define SPIPC0_EN0FUN_MASK BIT(0)
#define SPIINT_MASKALL 0x0101035F #define SPIINT_MASKALL 0x0101035F
#define SPI_INTLVL_1 0x000001FFu #define SPIINT_MASKINT 0x0000015F
#define SPI_INTLVL_0 0x00000000u #define SPI_INTLVL_1 0x000001FF
#define SPI_INTLVL_0 0x00000000
/* SPIDAT1 */ /* SPIDAT1 (upper 16 bit defines) */
#define SPIDAT1_CSHOLD_SHIFT 28 #define SPIDAT1_CSHOLD_MASK BIT(12)
#define SPIDAT1_CSNR_SHIFT 16
/* SPIGCR1 */
#define SPIGCR1_CLKMOD_MASK BIT(1) #define SPIGCR1_CLKMOD_MASK BIT(1)
#define SPIGCR1_MASTER_MASK BIT(0) #define SPIGCR1_MASTER_MASK BIT(0)
#define SPIGCR1_POWERDOWN_MASK BIT(8)
#define SPIGCR1_LOOPBACK_MASK BIT(16) #define SPIGCR1_LOOPBACK_MASK BIT(16)
#define SPIGCR1_SPIENA_MASK BIT(24)
/* SPIBUF */ /* SPIBUF */
#define SPIBUF_TXFULL_MASK BIT(29) #define SPIBUF_TXFULL_MASK BIT(29)
#define SPIBUF_RXEMPTY_MASK BIT(31) #define SPIBUF_RXEMPTY_MASK BIT(31)
/* SPIDELAY */
#define SPIDELAY_C2TDELAY_SHIFT 24
#define SPIDELAY_C2TDELAY_MASK (0xFF << SPIDELAY_C2TDELAY_SHIFT)
#define SPIDELAY_T2CDELAY_SHIFT 16
#define SPIDELAY_T2CDELAY_MASK (0xFF << SPIDELAY_T2CDELAY_SHIFT)
#define SPIDELAY_T2EDELAY_SHIFT 8
#define SPIDELAY_T2EDELAY_MASK (0xFF << SPIDELAY_T2EDELAY_SHIFT)
#define SPIDELAY_C2EDELAY_SHIFT 0
#define SPIDELAY_C2EDELAY_MASK 0xFF
/* Error Masks */ /* Error Masks */
#define SPIFLG_DLEN_ERR_MASK BIT(0) #define SPIFLG_DLEN_ERR_MASK BIT(0)
#define SPIFLG_TIMEOUT_MASK BIT(1) #define SPIFLG_TIMEOUT_MASK BIT(1)
...@@ -87,29 +92,13 @@ ...@@ -87,29 +92,13 @@
#define SPIFLG_DESYNC_MASK BIT(3) #define SPIFLG_DESYNC_MASK BIT(3)
#define SPIFLG_BITERR_MASK BIT(4) #define SPIFLG_BITERR_MASK BIT(4)
#define SPIFLG_OVRRUN_MASK BIT(6) #define SPIFLG_OVRRUN_MASK BIT(6)
#define SPIFLG_RX_INTR_MASK BIT(8)
#define SPIFLG_TX_INTR_MASK BIT(9)
#define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24) #define SPIFLG_BUF_INIT_ACTIVE_MASK BIT(24)
#define SPIFLG_MASK (SPIFLG_DLEN_ERR_MASK \ #define SPIFLG_ERROR_MASK (SPIFLG_DLEN_ERR_MASK \
| SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \ | SPIFLG_TIMEOUT_MASK | SPIFLG_PARERR_MASK \
| SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \ | SPIFLG_DESYNC_MASK | SPIFLG_BITERR_MASK \
| SPIFLG_OVRRUN_MASK | SPIFLG_RX_INTR_MASK \ | SPIFLG_OVRRUN_MASK)
| SPIFLG_TX_INTR_MASK \
| SPIFLG_BUF_INIT_ACTIVE_MASK)
#define SPIINT_DLEN_ERR_INTR BIT(0)
#define SPIINT_TIMEOUT_INTR BIT(1)
#define SPIINT_PARERR_INTR BIT(2)
#define SPIINT_DESYNC_INTR BIT(3)
#define SPIINT_BITERR_INTR BIT(4)
#define SPIINT_OVRRUN_INTR BIT(6)
#define SPIINT_RX_INTR BIT(8)
#define SPIINT_TX_INTR BIT(9)
#define SPIINT_DMA_REQ_EN BIT(16)
#define SPIINT_ENABLE_HIGHZ BIT(24)
#define SPI_T2CDELAY_SHIFT 16 #define SPIINT_DMA_REQ_EN BIT(16)
#define SPI_C2TDELAY_SHIFT 24
/* SPI Controller registers */ /* SPI Controller registers */
#define SPIGCR0 0x00 #define SPIGCR0 0x00
...@@ -118,44 +107,18 @@ ...@@ -118,44 +107,18 @@
#define SPILVL 0x0c #define SPILVL 0x0c
#define SPIFLG 0x10 #define SPIFLG 0x10
#define SPIPC0 0x14 #define SPIPC0 0x14
#define SPIPC1 0x18
#define SPIPC2 0x1c
#define SPIPC3 0x20
#define SPIPC4 0x24
#define SPIPC5 0x28
#define SPIPC6 0x2c
#define SPIPC7 0x30
#define SPIPC8 0x34
#define SPIDAT0 0x38
#define SPIDAT1 0x3c #define SPIDAT1 0x3c
#define SPIBUF 0x40 #define SPIBUF 0x40
#define SPIEMU 0x44
#define SPIDELAY 0x48 #define SPIDELAY 0x48
#define SPIDEF 0x4c #define SPIDEF 0x4c
#define SPIFMT0 0x50 #define SPIFMT0 0x50
#define SPIFMT1 0x54
#define SPIFMT2 0x58
#define SPIFMT3 0x5c
#define TGINTVEC0 0x60
#define TGINTVEC1 0x64
struct davinci_spi_slave {
u32 cmd_to_write;
u32 clk_ctrl_to_write;
u32 bytes_per_word;
u8 active_cs;
};
/* We have 2 DMA channels per CS, one for RX and one for TX */ /* We have 2 DMA channels per CS, one for RX and one for TX */
struct davinci_spi_dma { struct davinci_spi_dma {
int dma_tx_channel; int tx_channel;
int dma_rx_channel; int rx_channel;
int dma_tx_sync_dev; int dummy_param_slot;
int dma_rx_sync_dev;
enum dma_event_q eventq; enum dma_event_q eventq;
struct completion dma_tx_completion;
struct completion dma_rx_completion;
}; };
/* SPI Controller driver's private data. */ /* SPI Controller driver's private data. */
...@@ -166,58 +129,63 @@ struct davinci_spi { ...@@ -166,58 +129,63 @@ struct davinci_spi {
u8 version; u8 version;
resource_size_t pbase; resource_size_t pbase;
void __iomem *base; void __iomem *base;
size_t region_size;
u32 irq; u32 irq;
struct completion done; struct completion done;
const void *tx; const void *tx;
void *rx; void *rx;
u8 *tmp_buf; #define SPI_TMP_BUFSZ (SMP_CACHE_BYTES + 1)
int count; u8 rx_tmp_buf[SPI_TMP_BUFSZ];
struct davinci_spi_dma *dma_channels; int rcount;
int wcount;
struct davinci_spi_dma dma;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
void (*get_rx)(u32 rx_data, struct davinci_spi *); void (*get_rx)(u32 rx_data, struct davinci_spi *);
u32 (*get_tx)(struct davinci_spi *); u32 (*get_tx)(struct davinci_spi *);
struct davinci_spi_slave slave[SPI_MAX_CHIPSELECT]; u8 bytes_per_word[SPI_MAX_CHIPSELECT];
}; };
static unsigned use_dma; static struct davinci_spi_config davinci_spi_default_cfg;
static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *davinci_spi) static void davinci_spi_rx_buf_u8(u32 data, struct davinci_spi *dspi)
{ {
u8 *rx = davinci_spi->rx; if (dspi->rx) {
u8 *rx = dspi->rx;
*rx++ = (u8)data; *rx++ = (u8)data;
davinci_spi->rx = rx; dspi->rx = rx;
}
} }
static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *davinci_spi) static void davinci_spi_rx_buf_u16(u32 data, struct davinci_spi *dspi)
{ {
u16 *rx = davinci_spi->rx; if (dspi->rx) {
u16 *rx = dspi->rx;
*rx++ = (u16)data; *rx++ = (u16)data;
davinci_spi->rx = rx; dspi->rx = rx;
}
} }
static u32 davinci_spi_tx_buf_u8(struct davinci_spi *davinci_spi) static u32 davinci_spi_tx_buf_u8(struct davinci_spi *dspi)
{ {
u32 data; u32 data = 0;
const u8 *tx = davinci_spi->tx; if (dspi->tx) {
const u8 *tx = dspi->tx;
data = *tx++; data = *tx++;
davinci_spi->tx = tx; dspi->tx = tx;
}
return data; return data;
} }
static u32 davinci_spi_tx_buf_u16(struct davinci_spi *davinci_spi) static u32 davinci_spi_tx_buf_u16(struct davinci_spi *dspi)
{ {
u32 data; u32 data = 0;
const u16 *tx = davinci_spi->tx; if (dspi->tx) {
const u16 *tx = dspi->tx;
data = *tx++; data = *tx++;
davinci_spi->tx = tx; dspi->tx = tx;
}
return data; return data;
} }
...@@ -237,54 +205,66 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits) ...@@ -237,54 +205,66 @@ static inline void clear_io_bits(void __iomem *addr, u32 bits)
iowrite32(v, addr); iowrite32(v, addr);
} }
static inline void set_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
{
set_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
}
static inline void clear_fmt_bits(void __iomem *addr, u32 bits, int cs_num)
{
clear_io_bits(addr + SPIFMT0 + (0x4 * cs_num), bits);
}
static void davinci_spi_set_dma_req(const struct spi_device *spi, int enable)
{
struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
if (enable)
set_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
else
clear_io_bits(davinci_spi->base + SPIINT, SPIINT_DMA_REQ_EN);
}
/* /*
* Interface to control the chip select signal * Interface to control the chip select signal
*/ */
static void davinci_spi_chipselect(struct spi_device *spi, int value) static void davinci_spi_chipselect(struct spi_device *spi, int value)
{ {
struct davinci_spi *davinci_spi; struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
u32 data1_reg_val = 0; u8 chip_sel = spi->chip_select;
u16 spidat1 = CS_DEFAULT;
bool gpio_chipsel = false;
dspi = spi_master_get_devdata(spi->master);
pdata = dspi->pdata;
davinci_spi = spi_master_get_devdata(spi->master); if (pdata->chip_sel && chip_sel < pdata->num_chipselect &&
pdata = davinci_spi->pdata; pdata->chip_sel[chip_sel] != SPI_INTERN_CS)
gpio_chipsel = true;
/* /*
* Board specific chip select logic decides the polarity and cs * Board specific chip select logic decides the polarity and cs
* line for the controller * line for the controller
*/ */
if (value == BITBANG_CS_INACTIVE) { if (gpio_chipsel) {
set_io_bits(davinci_spi->base + SPIDEF, CS_DEFAULT); if (value == BITBANG_CS_ACTIVE)
gpio_set_value(pdata->chip_sel[chip_sel], 0);
data1_reg_val |= CS_DEFAULT << SPIDAT1_CSNR_SHIFT; else
iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); gpio_set_value(pdata->chip_sel[chip_sel], 1);
} else {
if (value == BITBANG_CS_ACTIVE) {
spidat1 |= SPIDAT1_CSHOLD_MASK;
spidat1 &= ~(0x1 << chip_sel);
}
while ((ioread32(davinci_spi->base + SPIBUF) iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
& SPIBUF_RXEMPTY_MASK) == 0)
cpu_relax();
} }
} }
/**
* davinci_spi_get_prescale - Calculates the correct prescale value
* @maxspeed_hz: the maximum rate the SPI clock can run at
*
* This function calculates the prescale value that generates a clock rate
* less than or equal to the specified maximum.
*
* Returns: calculated prescale - 1 for easy programming into SPI registers
* or negative error number if valid prescalar cannot be updated.
*/
static inline int davinci_spi_get_prescale(struct davinci_spi *dspi,
u32 max_speed_hz)
{
int ret;
ret = DIV_ROUND_UP(clk_get_rate(dspi->clk), max_speed_hz);
if (ret < 3 || ret > 256)
return -EINVAL;
return ret - 1;
}
/** /**
* davinci_spi_setup_transfer - This functions will determine transfer method * davinci_spi_setup_transfer - This functions will determine transfer method
* @spi: spi device on which data transfer to be done * @spi: spi device on which data transfer to be done
...@@ -298,13 +278,15 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -298,13 +278,15 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
struct davinci_spi *davinci_spi; struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata; struct davinci_spi_config *spicfg;
u8 bits_per_word = 0; u8 bits_per_word = 0;
u32 hz = 0, prescale = 0, clkspeed; u32 hz = 0, spifmt = 0, prescale = 0;
davinci_spi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
pdata = davinci_spi->pdata; spicfg = (struct davinci_spi_config *)spi->controller_data;
if (!spicfg)
spicfg = &davinci_spi_default_cfg;
if (t) { if (t) {
bits_per_word = t->bits_per_word; bits_per_word = t->bits_per_word;
...@@ -320,111 +302,83 @@ static int davinci_spi_setup_transfer(struct spi_device *spi, ...@@ -320,111 +302,83 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
* 8bit, 16bit or 32bit transfer * 8bit, 16bit or 32bit transfer
*/ */
if (bits_per_word <= 8 && bits_per_word >= 2) { if (bits_per_word <= 8 && bits_per_word >= 2) {
davinci_spi->get_rx = davinci_spi_rx_buf_u8; dspi->get_rx = davinci_spi_rx_buf_u8;
davinci_spi->get_tx = davinci_spi_tx_buf_u8; dspi->get_tx = davinci_spi_tx_buf_u8;
davinci_spi->slave[spi->chip_select].bytes_per_word = 1; dspi->bytes_per_word[spi->chip_select] = 1;
} else if (bits_per_word <= 16 && bits_per_word >= 2) { } else if (bits_per_word <= 16 && bits_per_word >= 2) {
davinci_spi->get_rx = davinci_spi_rx_buf_u16; dspi->get_rx = davinci_spi_rx_buf_u16;
davinci_spi->get_tx = davinci_spi_tx_buf_u16; dspi->get_tx = davinci_spi_tx_buf_u16;
davinci_spi->slave[spi->chip_select].bytes_per_word = 2; dspi->bytes_per_word[spi->chip_select] = 2;
} else } else
return -EINVAL; return -EINVAL;
if (!hz) if (!hz)
hz = spi->max_speed_hz; hz = spi->max_speed_hz;
clear_fmt_bits(davinci_spi->base, SPIFMT_CHARLEN_MASK, /* Set up SPIFMTn register, unique to this chipselect. */
spi->chip_select);
set_fmt_bits(davinci_spi->base, bits_per_word & 0x1f,
spi->chip_select);
clkspeed = clk_get_rate(davinci_spi->clk); prescale = davinci_spi_get_prescale(dspi, hz);
if (hz > clkspeed / 2) if (prescale < 0)
prescale = 1 << 8; return prescale;
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); spifmt = (prescale << SPIFMT_PRESCALE_SHIFT) | (bits_per_word & 0x1f);
set_fmt_bits(davinci_spi->base, prescale, spi->chip_select);
return 0; if (spi->mode & SPI_LSB_FIRST)
} spifmt |= SPIFMT_SHIFTDIR_MASK;
static void davinci_spi_dma_rx_callback(unsigned lch, u16 ch_status, void *data) if (spi->mode & SPI_CPOL)
{ spifmt |= SPIFMT_POLARITY_MASK;
struct spi_device *spi = (struct spi_device *)data;
struct davinci_spi *davinci_spi;
struct davinci_spi_dma *davinci_spi_dma;
struct davinci_spi_platform_data *pdata;
davinci_spi = spi_master_get_devdata(spi->master); if (!(spi->mode & SPI_CPHA))
davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]); spifmt |= SPIFMT_PHASE_MASK;
pdata = davinci_spi->pdata;
if (ch_status == DMA_COMPLETE) /*
edma_stop(davinci_spi_dma->dma_rx_channel); * Version 1 hardware supports two basic SPI modes:
else * - Standard SPI mode uses 4 pins, with chipselect
edma_clean_channel(davinci_spi_dma->dma_rx_channel); * - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
* (distinct from SPI_3WIRE, with just one data wire;
* or similar variants without MOSI or without MISO)
*
* Version 2 hardware supports an optional handshaking signal,
* so it can support two more modes:
* - 5 pin SPI variant is standard SPI plus SPI_READY
* - 4 pin with enable is (SPI_READY | SPI_NO_CS)
*/
complete(&davinci_spi_dma->dma_rx_completion); if (dspi->version == SPI_VERSION_2) {
/* We must disable the DMA RX request */
davinci_spi_set_dma_req(spi, 0);
}
static void davinci_spi_dma_tx_callback(unsigned lch, u16 ch_status, void *data) u32 delay = 0;
{
struct spi_device *spi = (struct spi_device *)data;
struct davinci_spi *davinci_spi;
struct davinci_spi_dma *davinci_spi_dma;
struct davinci_spi_platform_data *pdata;
davinci_spi = spi_master_get_devdata(spi->master); spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
davinci_spi_dma = &(davinci_spi->dma_channels[spi->chip_select]); & SPIFMT_WDELAY_MASK);
pdata = davinci_spi->pdata;
if (ch_status == DMA_COMPLETE) if (spicfg->odd_parity)
edma_stop(davinci_spi_dma->dma_tx_channel); spifmt |= SPIFMT_ODD_PARITY_MASK;
else
edma_clean_channel(davinci_spi_dma->dma_tx_channel);
complete(&davinci_spi_dma->dma_tx_completion); if (spicfg->parity_enable)
/* We must disable the DMA TX request */ spifmt |= SPIFMT_PARITYENA_MASK;
davinci_spi_set_dma_req(spi, 0);
}
static int davinci_spi_request_dma(struct spi_device *spi) if (spicfg->timer_disable) {
{ spifmt |= SPIFMT_DISTIMER_MASK;
struct davinci_spi *davinci_spi; } else {
struct davinci_spi_dma *davinci_spi_dma; delay |= (spicfg->c2tdelay << SPIDELAY_C2TDELAY_SHIFT)
struct davinci_spi_platform_data *pdata; & SPIDELAY_C2TDELAY_MASK;
struct device *sdev; delay |= (spicfg->t2cdelay << SPIDELAY_T2CDELAY_SHIFT)
int r; & SPIDELAY_T2CDELAY_MASK;
}
davinci_spi = spi_master_get_devdata(spi->master);
davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
pdata = davinci_spi->pdata;
sdev = davinci_spi->bitbang.master->dev.parent;
r = edma_alloc_channel(davinci_spi_dma->dma_rx_sync_dev, if (spi->mode & SPI_READY) {
davinci_spi_dma_rx_callback, spi, spifmt |= SPIFMT_WAITENA_MASK;
davinci_spi_dma->eventq); delay |= (spicfg->t2edelay << SPIDELAY_T2EDELAY_SHIFT)
if (r < 0) { & SPIDELAY_T2EDELAY_MASK;
dev_dbg(sdev, "Unable to request DMA channel for SPI RX\n"); delay |= (spicfg->c2edelay << SPIDELAY_C2EDELAY_SHIFT)
return -EAGAIN; & SPIDELAY_C2EDELAY_MASK;
} }
davinci_spi_dma->dma_rx_channel = r;
r = edma_alloc_channel(davinci_spi_dma->dma_tx_sync_dev, iowrite32(delay, dspi->base + SPIDELAY);
davinci_spi_dma_tx_callback, spi,
davinci_spi_dma->eventq);
if (r < 0) {
edma_free_channel(davinci_spi_dma->dma_rx_channel);
davinci_spi_dma->dma_rx_channel = -1;
dev_dbg(sdev, "Unable to request DMA channel for SPI TX\n");
return -EAGAIN;
} }
davinci_spi_dma->dma_tx_channel = r;
iowrite32(spifmt, dspi->base + SPIFMT0);
return 0; return 0;
} }
...@@ -435,190 +389,40 @@ static int davinci_spi_request_dma(struct spi_device *spi) ...@@ -435,190 +389,40 @@ static int davinci_spi_request_dma(struct spi_device *spi)
* *
* This functions sets the default transfer method. * This functions sets the default transfer method.
*/ */
static int davinci_spi_setup(struct spi_device *spi) static int davinci_spi_setup(struct spi_device *spi)
{ {
int retval; int retval = 0;
struct davinci_spi *davinci_spi; struct davinci_spi *dspi;
struct davinci_spi_dma *davinci_spi_dma; struct davinci_spi_platform_data *pdata;
struct device *sdev;
davinci_spi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
sdev = davinci_spi->bitbang.master->dev.parent; pdata = dspi->pdata;
/* if bits per word length is zero then set it default 8 */ /* if bits per word length is zero then set it default 8 */
if (!spi->bits_per_word) if (!spi->bits_per_word)
spi->bits_per_word = 8; spi->bits_per_word = 8;
davinci_spi->slave[spi->chip_select].cmd_to_write = 0; if (!(spi->mode & SPI_NO_CS)) {
if ((pdata->chip_sel == NULL) ||
if (use_dma && davinci_spi->dma_channels) { (pdata->chip_sel[spi->chip_select] == SPI_INTERN_CS))
davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; set_io_bits(dspi->base + SPIPC0, 1 << spi->chip_select);
if ((davinci_spi_dma->dma_rx_channel == -1)
|| (davinci_spi_dma->dma_tx_channel == -1)) {
retval = davinci_spi_request_dma(spi);
if (retval < 0)
return retval;
}
} }
/*
* SPI in DaVinci and DA8xx operate between
* 600 KHz and 50 MHz
*/
if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) {
dev_dbg(sdev, "Operating frequency is not in acceptable "
"range\n");
return -EINVAL;
}
/*
* Set up SPIFMTn register, unique to this chipselect.
*
* NOTE: we could do all of these with one write. Also, some
* of the "version 2" features are found in chips that don't
* support all of them...
*/
if (spi->mode & SPI_LSB_FIRST)
set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
spi->chip_select);
else
clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
spi->chip_select);
if (spi->mode & SPI_CPOL)
set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
spi->chip_select);
else
clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
spi->chip_select);
if (!(spi->mode & SPI_CPHA))
set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
spi->chip_select);
else
clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
spi->chip_select);
/*
* Version 1 hardware supports two basic SPI modes:
* - Standard SPI mode uses 4 pins, with chipselect
* - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
* (distinct from SPI_3WIRE, with just one data wire;
* or similar variants without MOSI or without MISO)
*
* Version 2 hardware supports an optional handshaking signal,
* so it can support two more modes:
* - 5 pin SPI variant is standard SPI plus SPI_READY
* - 4 pin with enable is (SPI_READY | SPI_NO_CS)
*/
if (davinci_spi->version == SPI_VERSION_2) {
clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK,
spi->chip_select);
set_fmt_bits(davinci_spi->base,
(davinci_spi->pdata->wdelay
<< SPIFMT_WDELAY_SHIFT)
& SPIFMT_WDELAY_MASK,
spi->chip_select);
if (davinci_spi->pdata->odd_parity)
set_fmt_bits(davinci_spi->base,
SPIFMT_ODD_PARITY_MASK,
spi->chip_select);
else
clear_fmt_bits(davinci_spi->base,
SPIFMT_ODD_PARITY_MASK,
spi->chip_select);
if (davinci_spi->pdata->parity_enable)
set_fmt_bits(davinci_spi->base,
SPIFMT_PARITYENA_MASK,
spi->chip_select);
else
clear_fmt_bits(davinci_spi->base,
SPIFMT_PARITYENA_MASK,
spi->chip_select);
if (davinci_spi->pdata->wait_enable)
set_fmt_bits(davinci_spi->base,
SPIFMT_WAITENA_MASK,
spi->chip_select);
else
clear_fmt_bits(davinci_spi->base,
SPIFMT_WAITENA_MASK,
spi->chip_select);
if (davinci_spi->pdata->timer_disable)
set_fmt_bits(davinci_spi->base,
SPIFMT_DISTIMER_MASK,
spi->chip_select);
else
clear_fmt_bits(davinci_spi->base,
SPIFMT_DISTIMER_MASK,
spi->chip_select);
}
retval = davinci_spi_setup_transfer(spi, NULL);
return retval;
}
static void davinci_spi_cleanup(struct spi_device *spi)
{
struct davinci_spi *davinci_spi = spi_master_get_devdata(spi->master);
struct davinci_spi_dma *davinci_spi_dma;
davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
if (use_dma && davinci_spi->dma_channels) {
davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];
if ((davinci_spi_dma->dma_rx_channel != -1)
&& (davinci_spi_dma->dma_tx_channel != -1)) {
edma_free_channel(davinci_spi_dma->dma_tx_channel);
edma_free_channel(davinci_spi_dma->dma_rx_channel);
}
}
}
static int davinci_spi_bufs_prep(struct spi_device *spi,
struct davinci_spi *davinci_spi)
{
int op_mode = 0;
/*
* REVISIT unless devices disagree about SPI_LOOP or
* SPI_READY (SPI_NO_CS only allows one device!), this
* should not need to be done before each message...
* optimize for both flags staying cleared.
*/
op_mode = SPIPC0_DIFUN_MASK
| SPIPC0_DOFUN_MASK
| SPIPC0_CLKFUN_MASK;
if (!(spi->mode & SPI_NO_CS))
op_mode |= 1 << spi->chip_select;
if (spi->mode & SPI_READY) if (spi->mode & SPI_READY)
op_mode |= SPIPC0_SPIENA_MASK; set_io_bits(dspi->base + SPIPC0, SPIPC0_SPIENA_MASK);
iowrite32(op_mode, davinci_spi->base + SPIPC0);
if (spi->mode & SPI_LOOP) if (spi->mode & SPI_LOOP)
set_io_bits(davinci_spi->base + SPIGCR1, set_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
SPIGCR1_LOOPBACK_MASK);
else else
clear_io_bits(davinci_spi->base + SPIGCR1, clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);
SPIGCR1_LOOPBACK_MASK);
return 0; return retval;
} }
static int davinci_spi_check_error(struct davinci_spi *davinci_spi, static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
int int_status)
{ {
struct device *sdev = davinci_spi->bitbang.master->dev.parent; struct device *sdev = dspi->bitbang.master->dev.parent;
if (int_status & SPIFLG_TIMEOUT_MASK) { if (int_status & SPIFLG_TIMEOUT_MASK) {
dev_dbg(sdev, "SPI Time-out Error\n"); dev_dbg(sdev, "SPI Time-out Error\n");
...@@ -633,7 +437,7 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi, ...@@ -633,7 +437,7 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
return -EIO; return -EIO;
} }
if (davinci_spi->version == SPI_VERSION_2) { if (dspi->version == SPI_VERSION_2) {
if (int_status & SPIFLG_DLEN_ERR_MASK) { if (int_status & SPIFLG_DLEN_ERR_MASK) {
dev_dbg(sdev, "SPI Data Length Error\n"); dev_dbg(sdev, "SPI Data Length Error\n");
return -EIO; return -EIO;
...@@ -646,10 +450,6 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi, ...@@ -646,10 +450,6 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
dev_dbg(sdev, "SPI Data Overrun error\n"); dev_dbg(sdev, "SPI Data Overrun error\n");
return -EIO; return -EIO;
} }
if (int_status & SPIFLG_TX_INTR_MASK) {
dev_dbg(sdev, "SPI TX intr bit set\n");
return -EIO;
}
if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) { if (int_status & SPIFLG_BUF_INIT_ACTIVE_MASK) {
dev_dbg(sdev, "SPI Buffer Init Active\n"); dev_dbg(sdev, "SPI Buffer Init Active\n");
return -EBUSY; return -EBUSY;
...@@ -660,366 +460,339 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi, ...@@ -660,366 +460,339 @@ static int davinci_spi_check_error(struct davinci_spi *davinci_spi,
} }
/** /**
* davinci_spi_bufs - functions which will handle transfer data * davinci_spi_process_events - check for and handle any SPI controller events
* @spi: spi device on which data transfer to be done * @dspi: the controller data
* @t: spi transfer in which transfer info is filled
* *
* This function will put data to be transferred into data register * This function will check the SPIFLG register and handle any events that are
* of SPI controller and then wait until the completion will be marked * detected there
* by the IRQ Handler.
*/ */
static int davinci_spi_bufs_pio(struct spi_device *spi, struct spi_transfer *t) static int davinci_spi_process_events(struct davinci_spi *dspi)
{ {
struct davinci_spi *davinci_spi; u32 buf, status, errors = 0, spidat1;
int int_status, count, ret;
u8 conv, tmp;
u32 tx_data, data1_reg_val;
u32 buf_val, flg_val;
struct davinci_spi_platform_data *pdata;
davinci_spi = spi_master_get_devdata(spi->master);
pdata = davinci_spi->pdata;
davinci_spi->tx = t->tx_buf;
davinci_spi->rx = t->rx_buf;
/* convert len to words based on bits_per_word */
conv = davinci_spi->slave[spi->chip_select].bytes_per_word;
davinci_spi->count = t->len / conv;
INIT_COMPLETION(davinci_spi->done);
ret = davinci_spi_bufs_prep(spi, davinci_spi);
if (ret)
return ret;
/* Enable SPI */
set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) |
(pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
davinci_spi->base + SPIDELAY);
count = davinci_spi->count;
data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
tmp = ~(0x1 << spi->chip_select);
clear_io_bits(davinci_spi->base + SPIDEF, ~tmp);
data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT; buf = ioread32(dspi->base + SPIBUF);
while ((ioread32(davinci_spi->base + SPIBUF) if (dspi->rcount > 0 && !(buf & SPIBUF_RXEMPTY_MASK)) {
& SPIBUF_RXEMPTY_MASK) == 0) dspi->get_rx(buf & 0xFFFF, dspi);
cpu_relax(); dspi->rcount--;
}
/* Determine the command to execute READ or WRITE */
if (t->tx_buf) {
clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
while (1) {
tx_data = davinci_spi->get_tx(davinci_spi);
data1_reg_val &= ~(0xFFFF);
data1_reg_val |= (0xFFFF & tx_data);
buf_val = ioread32(davinci_spi->base + SPIBUF); status = ioread32(dspi->base + SPIFLG);
if ((buf_val & SPIBUF_TXFULL_MASK) == 0) {
iowrite32(data1_reg_val,
davinci_spi->base + SPIDAT1);
count--; if (unlikely(status & SPIFLG_ERROR_MASK)) {
errors = status & SPIFLG_ERROR_MASK;
goto out;
} }
while (ioread32(davinci_spi->base + SPIBUF)
& SPIBUF_RXEMPTY_MASK)
cpu_relax();
/* getting the returned byte */ if (dspi->wcount > 0 && !(buf & SPIBUF_TXFULL_MASK)) {
if (t->rx_buf) { spidat1 = ioread32(dspi->base + SPIDAT1);
buf_val = ioread32(davinci_spi->base + SPIBUF); dspi->wcount--;
davinci_spi->get_rx(buf_val, davinci_spi); spidat1 &= ~0xFFFF;
} spidat1 |= 0xFFFF & dspi->get_tx(dspi);
if (count <= 0) iowrite32(spidat1, dspi->base + SPIDAT1);
break;
} }
} else {
if (pdata->poll_mode) {
while (1) {
/* keeps the serial clock going */
if ((ioread32(davinci_spi->base + SPIBUF)
& SPIBUF_TXFULL_MASK) == 0)
iowrite32(data1_reg_val,
davinci_spi->base + SPIDAT1);
while (ioread32(davinci_spi->base + SPIBUF) &
SPIBUF_RXEMPTY_MASK)
cpu_relax();
flg_val = ioread32(davinci_spi->base + SPIFLG);
buf_val = ioread32(davinci_spi->base + SPIBUF);
davinci_spi->get_rx(buf_val, davinci_spi);
count--; out:
if (count <= 0) return errors;
break; }
}
} else { /* Receive in Interrupt mode */
int i;
for (i = 0; i < davinci_spi->count; i++) { static void davinci_spi_dma_callback(unsigned lch, u16 status, void *data)
set_io_bits(davinci_spi->base + SPIINT, {
SPIINT_BITERR_INTR struct davinci_spi *dspi = data;
| SPIINT_OVRRUN_INTR struct davinci_spi_dma *dma = &dspi->dma;
| SPIINT_RX_INTR);
iowrite32(data1_reg_val, edma_stop(lch);
davinci_spi->base + SPIDAT1);
while (ioread32(davinci_spi->base + SPIINT) & if (status == DMA_COMPLETE) {
SPIINT_RX_INTR) if (lch == dma->rx_channel)
cpu_relax(); dspi->rcount = 0;
} if (lch == dma->tx_channel)
iowrite32((data1_reg_val & 0x0ffcffff), dspi->wcount = 0;
davinci_spi->base + SPIDAT1);
}
} }
/* if ((!dspi->wcount && !dspi->rcount) || (status != DMA_COMPLETE))
* Check for bit error, desync error,parity error,timeout error and complete(&dspi->done);
* receive overflow errors
*/
int_status = ioread32(davinci_spi->base + SPIFLG);
ret = davinci_spi_check_error(davinci_spi, int_status);
if (ret != 0)
return ret;
/* SPI Framework maintains the count only in bytes so convert back */
davinci_spi->count *= conv;
return t->len;
} }
#define DAVINCI_DMA_DATA_TYPE_S8 0x01 /**
#define DAVINCI_DMA_DATA_TYPE_S16 0x02 * davinci_spi_bufs - functions which will handle transfer data
#define DAVINCI_DMA_DATA_TYPE_S32 0x04 * @spi: spi device on which data transfer to be done
* @t: spi transfer in which transfer info is filled
static int davinci_spi_bufs_dma(struct spi_device *spi, struct spi_transfer *t) *
* This function will put data to be transferred into data register
* of SPI controller and then wait until the completion will be marked
* by the IRQ Handler.
*/
static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
{ {
struct davinci_spi *davinci_spi; struct davinci_spi *dspi;
int int_status = 0; int data_type, ret;
int count, temp_count; u32 tx_data, spidat1;
u8 conv = 1; u32 errors = 0;
u8 tmp; struct davinci_spi_config *spicfg;
u32 data1_reg_val;
struct davinci_spi_dma *davinci_spi_dma;
int word_len, data_type, ret;
unsigned long tx_reg, rx_reg;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
unsigned uninitialized_var(rx_buf_count);
struct device *sdev; struct device *sdev;
davinci_spi = spi_master_get_devdata(spi->master); dspi = spi_master_get_devdata(spi->master);
pdata = davinci_spi->pdata; pdata = dspi->pdata;
sdev = davinci_spi->bitbang.master->dev.parent; spicfg = (struct davinci_spi_config *)spi->controller_data;
if (!spicfg)
davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select]; spicfg = &davinci_spi_default_cfg;
sdev = dspi->bitbang.master->dev.parent;
tx_reg = (unsigned long)davinci_spi->pbase + SPIDAT1;
rx_reg = (unsigned long)davinci_spi->pbase + SPIBUF;
davinci_spi->tx = t->tx_buf;
davinci_spi->rx = t->rx_buf;
/* convert len to words based on bits_per_word */ /* convert len to words based on bits_per_word */
conv = davinci_spi->slave[spi->chip_select].bytes_per_word; data_type = dspi->bytes_per_word[spi->chip_select];
davinci_spi->count = t->len / conv;
INIT_COMPLETION(davinci_spi->done);
init_completion(&davinci_spi_dma->dma_rx_completion);
init_completion(&davinci_spi_dma->dma_tx_completion);
word_len = conv * 8; dspi->tx = t->tx_buf;
dspi->rx = t->rx_buf;
dspi->wcount = t->len / data_type;
dspi->rcount = dspi->wcount;
if (word_len <= 8) spidat1 = ioread32(dspi->base + SPIDAT1);
data_type = DAVINCI_DMA_DATA_TYPE_S8;
else if (word_len <= 16)
data_type = DAVINCI_DMA_DATA_TYPE_S16;
else if (word_len <= 32)
data_type = DAVINCI_DMA_DATA_TYPE_S32;
else
return -EINVAL;
ret = davinci_spi_bufs_prep(spi, davinci_spi);
if (ret)
return ret;
/* Put delay val if required */ clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
iowrite32(0 | (pdata->c2tdelay << SPI_C2TDELAY_SHIFT) | set_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
(pdata->t2cdelay << SPI_T2CDELAY_SHIFT),
davinci_spi->base + SPIDELAY);
count = davinci_spi->count; /* the number of elements */ INIT_COMPLETION(dspi->done);
data1_reg_val = pdata->cs_hold << SPIDAT1_CSHOLD_SHIFT;
/* CS default = 0xFF */ if (spicfg->io_type == SPI_IO_TYPE_INTR)
tmp = ~(0x1 << spi->chip_select); set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
clear_io_bits(davinci_spi->base + SPIDEF, ~tmp); if (spicfg->io_type != SPI_IO_TYPE_DMA) {
/* start the transfer */
data1_reg_val |= tmp << SPIDAT1_CSNR_SHIFT; dspi->wcount--;
tx_data = dspi->get_tx(dspi);
spidat1 &= 0xFFFF0000;
spidat1 |= tx_data & 0xFFFF;
iowrite32(spidat1, dspi->base + SPIDAT1);
} else {
struct davinci_spi_dma *dma;
unsigned long tx_reg, rx_reg;
struct edmacc_param param;
void *rx_buf;
/* disable all interrupts for dma transfers */ dma = &dspi->dma;
clear_io_bits(davinci_spi->base + SPIINT, SPIINT_MASKALL);
/* Disable SPI to write configuration bits in SPIDAT */
clear_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1);
/* Enable SPI */
set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
while ((ioread32(davinci_spi->base + SPIBUF) tx_reg = (unsigned long)dspi->pbase + SPIDAT1;
& SPIBUF_RXEMPTY_MASK) == 0) rx_reg = (unsigned long)dspi->pbase + SPIBUF;
cpu_relax();
/*
* Transmit DMA setup
*
* If there is transmit data, map the transmit buffer, set it
* as the source of data and set the source B index to data
* size. If there is no transmit data, set the transmit register
* as the source of data, and set the source B index to zero.
*
* The destination is always the transmit register itself. And
* the destination never increments.
*/
if (t->tx_buf) { if (t->tx_buf) {
t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf, count, t->tx_dma = dma_map_single(&spi->dev, (void *)t->tx_buf,
DMA_TO_DEVICE); dspi->wcount, DMA_TO_DEVICE);
if (dma_mapping_error(&spi->dev, t->tx_dma)) {
dev_dbg(sdev, "Unable to DMA map a %d bytes"
" TX buffer\n", count);
return -ENOMEM;
}
temp_count = count;
} else {
/* We need TX clocking for RX transaction */
t->tx_dma = dma_map_single(&spi->dev,
(void *)davinci_spi->tmp_buf, count + 1,
DMA_TO_DEVICE);
if (dma_mapping_error(&spi->dev, t->tx_dma)) { if (dma_mapping_error(&spi->dev, t->tx_dma)) {
dev_dbg(sdev, "Unable to DMA map a %d bytes" dev_dbg(sdev, "Unable to DMA map %d bytes"
" TX tmp buffer\n", count); "TX buffer\n", dspi->wcount);
return -ENOMEM; return -ENOMEM;
} }
temp_count = count + 1;
} }
edma_set_transfer_params(davinci_spi_dma->dma_tx_channel, param.opt = TCINTEN | EDMA_TCC(dma->tx_channel);
data_type, temp_count, 1, 0, ASYNC); param.src = t->tx_buf ? t->tx_dma : tx_reg;
edma_set_dest(davinci_spi_dma->dma_tx_channel, tx_reg, INCR, W8BIT); param.a_b_cnt = dspi->wcount << 16 | data_type;
edma_set_src(davinci_spi_dma->dma_tx_channel, t->tx_dma, INCR, W8BIT); param.dst = tx_reg;
edma_set_src_index(davinci_spi_dma->dma_tx_channel, data_type, 0); param.src_dst_bidx = t->tx_buf ? data_type : 0;
edma_set_dest_index(davinci_spi_dma->dma_tx_channel, 0, 0); param.link_bcntrld = 0xffff;
param.src_dst_cidx = 0;
param.ccnt = 1;
edma_write_slot(dma->tx_channel, &param);
edma_link(dma->tx_channel, dma->dummy_param_slot);
/*
* Receive DMA setup
*
* If there is receive buffer, use it to receive data. If there
* is none provided, use a temporary receive buffer. Set the
* destination B index to 0 so effectively only one byte is used
* in the temporary buffer (address does not increment).
*
* The source of receive data is the receive data register. The
* source address never increments.
*/
if (t->rx_buf) { if (t->rx_buf) {
/* initiate transaction */ rx_buf = t->rx_buf;
iowrite32(data1_reg_val, davinci_spi->base + SPIDAT1); rx_buf_count = dspi->rcount;
} else {
rx_buf = dspi->rx_tmp_buf;
rx_buf_count = sizeof(dspi->rx_tmp_buf);
}
t->rx_dma = dma_map_single(&spi->dev, (void *)t->rx_buf, count, t->rx_dma = dma_map_single(&spi->dev, rx_buf, rx_buf_count,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
if (dma_mapping_error(&spi->dev, t->rx_dma)) { if (dma_mapping_error(&spi->dev, t->rx_dma)) {
dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n", dev_dbg(sdev, "Couldn't DMA map a %d bytes RX buffer\n",
count); rx_buf_count);
if (t->tx_buf != NULL) if (t->tx_buf)
dma_unmap_single(NULL, t->tx_dma, dma_unmap_single(NULL, t->tx_dma, dspi->wcount,
count, DMA_TO_DEVICE); DMA_TO_DEVICE);
return -ENOMEM; return -ENOMEM;
} }
edma_set_transfer_params(davinci_spi_dma->dma_rx_channel,
data_type, count, 1, 0, ASYNC);
edma_set_src(davinci_spi_dma->dma_rx_channel,
rx_reg, INCR, W8BIT);
edma_set_dest(davinci_spi_dma->dma_rx_channel,
t->rx_dma, INCR, W8BIT);
edma_set_src_index(davinci_spi_dma->dma_rx_channel, 0, 0);
edma_set_dest_index(davinci_spi_dma->dma_rx_channel,
data_type, 0);
}
if ((t->tx_buf) || (t->rx_buf)) param.opt = TCINTEN | EDMA_TCC(dma->rx_channel);
edma_start(davinci_spi_dma->dma_tx_channel); param.src = rx_reg;
param.a_b_cnt = dspi->rcount << 16 | data_type;
param.dst = t->rx_dma;
param.src_dst_bidx = (t->rx_buf ? data_type : 0) << 16;
param.link_bcntrld = 0xffff;
param.src_dst_cidx = 0;
param.ccnt = 1;
edma_write_slot(dma->rx_channel, &param);
if (pdata->cshold_bug)
iowrite16(spidat1 >> 16, dspi->base + SPIDAT1 + 2);
if (t->rx_buf) edma_start(dma->rx_channel);
edma_start(davinci_spi_dma->dma_rx_channel); edma_start(dma->tx_channel);
set_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
}
/* Wait for the transfer to complete */
if (spicfg->io_type != SPI_IO_TYPE_POLL) {
wait_for_completion_interruptible(&(dspi->done));
} else {
while (dspi->rcount > 0 || dspi->wcount > 0) {
errors = davinci_spi_process_events(dspi);
if (errors)
break;
cpu_relax();
}
}
if ((t->rx_buf) || (t->tx_buf)) clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
davinci_spi_set_dma_req(spi, 1); if (spicfg->io_type == SPI_IO_TYPE_DMA) {
if (t->tx_buf) if (t->tx_buf)
wait_for_completion_interruptible( dma_unmap_single(NULL, t->tx_dma, dspi->wcount,
&davinci_spi_dma->dma_tx_completion); DMA_TO_DEVICE);
if (t->rx_buf) dma_unmap_single(NULL, t->rx_dma, rx_buf_count,
wait_for_completion_interruptible( DMA_FROM_DEVICE);
&davinci_spi_dma->dma_rx_completion);
dma_unmap_single(NULL, t->tx_dma, temp_count, DMA_TO_DEVICE); clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
}
if (t->rx_buf) clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
dma_unmap_single(NULL, t->rx_dma, count, DMA_FROM_DEVICE); set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
/* /*
* Check for bit error, desync error,parity error,timeout error and * Check for bit error, desync error,parity error,timeout error and
* receive overflow errors * receive overflow errors
*/ */
int_status = ioread32(davinci_spi->base + SPIFLG); if (errors) {
ret = davinci_spi_check_error(dspi, errors);
ret = davinci_spi_check_error(davinci_spi, int_status); WARN(!ret, "%s: error reported but no error found!\n",
if (ret != 0) dev_name(&spi->dev));
return ret; return ret;
}
/* SPI Framework maintains the count only in bytes so convert back */ if (dspi->rcount != 0 || dspi->wcount != 0) {
davinci_spi->count *= conv; dev_err(sdev, "SPI data transfer error\n");
return -EIO;
}
return t->len; return t->len;
} }
/** /**
* davinci_spi_irq - IRQ handler for DaVinci SPI * davinci_spi_irq - Interrupt handler for SPI Master Controller
* @irq: IRQ number for this SPI Master * @irq: IRQ number for this SPI Master
* @context_data: structure for SPI Master controller davinci_spi * @context_data: structure for SPI Master controller davinci_spi
*
* ISR will determine that interrupt arrives either for READ or WRITE command.
* According to command it will do the appropriate action. It will check
* transfer length and if it is not zero then dispatch transfer command again.
* If transfer length is zero then it will indicate the COMPLETION so that
* davinci_spi_bufs function can go ahead.
*/ */
static irqreturn_t davinci_spi_irq(s32 irq, void *context_data) static irqreturn_t davinci_spi_irq(s32 irq, void *data)
{ {
struct davinci_spi *davinci_spi = context_data; struct davinci_spi *dspi = data;
u32 int_status, rx_data = 0; int status;
irqreturn_t ret = IRQ_NONE;
int_status = ioread32(davinci_spi->base + SPIFLG); status = davinci_spi_process_events(dspi);
if (unlikely(status != 0))
clear_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
while ((int_status & SPIFLG_RX_INTR_MASK)) { if ((!dspi->rcount && !dspi->wcount) || status)
if (likely(int_status & SPIFLG_RX_INTR_MASK)) { complete(&dspi->done);
ret = IRQ_HANDLED;
rx_data = ioread32(davinci_spi->base + SPIBUF); return IRQ_HANDLED;
davinci_spi->get_rx(rx_data, davinci_spi); }
/* Disable Receive Interrupt */ static int davinci_spi_request_dma(struct davinci_spi *dspi)
iowrite32(~(SPIINT_RX_INTR | SPIINT_TX_INTR), {
davinci_spi->base + SPIINT); int r;
} else struct davinci_spi_dma *dma = &dspi->dma;
(void)davinci_spi_check_error(davinci_spi, int_status);
int_status = ioread32(davinci_spi->base + SPIFLG); r = edma_alloc_channel(dma->rx_channel, davinci_spi_dma_callback, dspi,
dma->eventq);
if (r < 0) {
pr_err("Unable to request DMA channel for SPI RX\n");
r = -EAGAIN;
goto rx_dma_failed;
} }
return ret; r = edma_alloc_channel(dma->tx_channel, davinci_spi_dma_callback, dspi,
dma->eventq);
if (r < 0) {
pr_err("Unable to request DMA channel for SPI TX\n");
r = -EAGAIN;
goto tx_dma_failed;
}
r = edma_alloc_slot(EDMA_CTLR(dma->tx_channel), EDMA_SLOT_ANY);
if (r < 0) {
pr_err("Unable to request SPI TX DMA param slot\n");
r = -EAGAIN;
goto param_failed;
}
dma->dummy_param_slot = r;
edma_link(dma->dummy_param_slot, dma->dummy_param_slot);
return 0;
param_failed:
edma_free_channel(dma->tx_channel);
tx_dma_failed:
edma_free_channel(dma->rx_channel);
rx_dma_failed:
return r;
} }
/** /**
* davinci_spi_probe - probe function for SPI Master Controller * davinci_spi_probe - probe function for SPI Master Controller
* @pdev: platform_device structure which contains plateform specific data * @pdev: platform_device structure which contains plateform specific data
*
* According to Linux Device Model this function will be invoked by Linux
* with platform_device struct which contains the device specific info.
* This function will map the SPI controller's memory, register IRQ,
* Reset SPI controller and setting its registers to default value.
* It will invoke spi_bitbang_start to create work queue so that client driver
* can register transfer method to work queue.
*/ */
static int davinci_spi_probe(struct platform_device *pdev) static int davinci_spi_probe(struct platform_device *pdev)
{ {
struct spi_master *master; struct spi_master *master;
struct davinci_spi *davinci_spi; struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata; struct davinci_spi_platform_data *pdata;
struct resource *r, *mem; struct resource *r, *mem;
resource_size_t dma_rx_chan = SPI_NO_RESOURCE; resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
resource_size_t dma_tx_chan = SPI_NO_RESOURCE; resource_size_t dma_tx_chan = SPI_NO_RESOURCE;
resource_size_t dma_eventq = SPI_NO_RESOURCE; resource_size_t dma_eventq = SPI_NO_RESOURCE;
int i = 0, ret = 0; int i = 0, ret = 0;
u32 spipc0;
pdata = pdev->dev.platform_data; pdata = pdev->dev.platform_data;
if (pdata == NULL) { if (pdata == NULL) {
...@@ -1035,8 +808,8 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -1035,8 +808,8 @@ static int davinci_spi_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, master); dev_set_drvdata(&pdev->dev, master);
davinci_spi = spi_master_get_devdata(master); dspi = spi_master_get_devdata(master);
if (davinci_spi == NULL) { if (dspi == NULL) {
ret = -ENOENT; ret = -ENOENT;
goto free_master; goto free_master;
} }
...@@ -1047,72 +820,58 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -1047,72 +820,58 @@ static int davinci_spi_probe(struct platform_device *pdev)
goto free_master; goto free_master;
} }
davinci_spi->pbase = r->start; dspi->pbase = r->start;
davinci_spi->region_size = resource_size(r); dspi->pdata = pdata;
davinci_spi->pdata = pdata;
mem = request_mem_region(r->start, davinci_spi->region_size, mem = request_mem_region(r->start, resource_size(r), pdev->name);
pdev->name);
if (mem == NULL) { if (mem == NULL) {
ret = -EBUSY; ret = -EBUSY;
goto free_master; goto free_master;
} }
davinci_spi->base = (struct davinci_spi_reg __iomem *) dspi->base = ioremap(r->start, resource_size(r));
ioremap(r->start, davinci_spi->region_size); if (dspi->base == NULL) {
if (davinci_spi->base == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto release_region; goto release_region;
} }
davinci_spi->irq = platform_get_irq(pdev, 0); dspi->irq = platform_get_irq(pdev, 0);
if (davinci_spi->irq <= 0) { if (dspi->irq <= 0) {
ret = -EINVAL; ret = -EINVAL;
goto unmap_io; goto unmap_io;
} }
ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED, ret = request_irq(dspi->irq, davinci_spi_irq, 0, dev_name(&pdev->dev),
dev_name(&pdev->dev), davinci_spi); dspi);
if (ret) if (ret)
goto unmap_io; goto unmap_io;
/* Allocate tmp_buf for tx_buf */ dspi->bitbang.master = spi_master_get(master);
davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL); if (dspi->bitbang.master == NULL) {
if (davinci_spi->tmp_buf == NULL) {
ret = -ENOMEM;
goto irq_free;
}
davinci_spi->bitbang.master = spi_master_get(master);
if (davinci_spi->bitbang.master == NULL) {
ret = -ENODEV; ret = -ENODEV;
goto free_tmp_buf; goto irq_free;
} }
davinci_spi->clk = clk_get(&pdev->dev, NULL); dspi->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(davinci_spi->clk)) { if (IS_ERR(dspi->clk)) {
ret = -ENODEV; ret = -ENODEV;
goto put_master; goto put_master;
} }
clk_enable(davinci_spi->clk); clk_enable(dspi->clk);
master->bus_num = pdev->id; master->bus_num = pdev->id;
master->num_chipselect = pdata->num_chipselect; master->num_chipselect = pdata->num_chipselect;
master->setup = davinci_spi_setup; master->setup = davinci_spi_setup;
master->cleanup = davinci_spi_cleanup;
davinci_spi->bitbang.chipselect = davinci_spi_chipselect; dspi->bitbang.chipselect = davinci_spi_chipselect;
davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer; dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
davinci_spi->version = pdata->version; dspi->version = pdata->version;
use_dma = pdata->use_dma;
davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP; dspi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
if (davinci_spi->version == SPI_VERSION_2) if (dspi->version == SPI_VERSION_2)
davinci_spi->bitbang.flags |= SPI_READY; dspi->bitbang.flags |= SPI_READY;
if (use_dma) {
r = platform_get_resource(pdev, IORESOURCE_DMA, 0); r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (r) if (r)
dma_rx_chan = r->start; dma_rx_chan = r->start;
...@@ -1122,89 +881,82 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -1122,89 +881,82 @@ static int davinci_spi_probe(struct platform_device *pdev)
r = platform_get_resource(pdev, IORESOURCE_DMA, 2); r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
if (r) if (r)
dma_eventq = r->start; dma_eventq = r->start;
}
if (!use_dma || dspi->bitbang.txrx_bufs = davinci_spi_bufs;
dma_rx_chan == SPI_NO_RESOURCE || if (dma_rx_chan != SPI_NO_RESOURCE &&
dma_tx_chan == SPI_NO_RESOURCE || dma_tx_chan != SPI_NO_RESOURCE &&
dma_eventq == SPI_NO_RESOURCE) { dma_eventq != SPI_NO_RESOURCE) {
davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio; dspi->dma.rx_channel = dma_rx_chan;
use_dma = 0; dspi->dma.tx_channel = dma_tx_chan;
} else { dspi->dma.eventq = dma_eventq;
davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
davinci_spi->dma_channels = kzalloc(master->num_chipselect ret = davinci_spi_request_dma(dspi);
* sizeof(struct davinci_spi_dma), GFP_KERNEL); if (ret)
if (davinci_spi->dma_channels == NULL) {
ret = -ENOMEM;
goto free_clk; goto free_clk;
}
for (i = 0; i < master->num_chipselect; i++) { dev_info(&pdev->dev, "DMA: supported\n");
davinci_spi->dma_channels[i].dma_rx_channel = -1; dev_info(&pdev->dev, "DMA: RX channel: %d, TX channel: %d, "
davinci_spi->dma_channels[i].dma_rx_sync_dev = "event queue: %d\n", dma_rx_chan, dma_tx_chan,
dma_rx_chan;
davinci_spi->dma_channels[i].dma_tx_channel = -1;
davinci_spi->dma_channels[i].dma_tx_sync_dev =
dma_tx_chan;
davinci_spi->dma_channels[i].eventq = dma_eventq;
}
dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n"
"Using RX channel = %d , TX channel = %d and "
"event queue = %d", dma_rx_chan, dma_tx_chan,
dma_eventq); dma_eventq);
} }
davinci_spi->get_rx = davinci_spi_rx_buf_u8; dspi->get_rx = davinci_spi_rx_buf_u8;
davinci_spi->get_tx = davinci_spi_tx_buf_u8; dspi->get_tx = davinci_spi_tx_buf_u8;
init_completion(&davinci_spi->done); init_completion(&dspi->done);
/* Reset In/OUT SPI module */ /* Reset In/OUT SPI module */
iowrite32(0, davinci_spi->base + SPIGCR0); iowrite32(0, dspi->base + SPIGCR0);
udelay(100); udelay(100);
iowrite32(1, davinci_spi->base + SPIGCR0); iowrite32(1, dspi->base + SPIGCR0);
/* Clock internal */ /* Set up SPIPC0. CS and ENA init is done in davinci_spi_setup */
if (davinci_spi->pdata->clk_internal) spipc0 = SPIPC0_DIFUN_MASK | SPIPC0_DOFUN_MASK | SPIPC0_CLKFUN_MASK;
set_io_bits(davinci_spi->base + SPIGCR1, iowrite32(spipc0, dspi->base + SPIPC0);
SPIGCR1_CLKMOD_MASK);
else
clear_io_bits(davinci_spi->base + SPIGCR1,
SPIGCR1_CLKMOD_MASK);
/* master mode default */ /* initialize chip selects */
set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK); if (pdata->chip_sel) {
for (i = 0; i < pdata->num_chipselect; i++) {
if (pdata->chip_sel[i] != SPI_INTERN_CS)
gpio_direction_output(pdata->chip_sel[i], 1);
}
}
if (davinci_spi->pdata->intr_level) if (pdata->intr_line)
iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL); iowrite32(SPI_INTLVL_1, dspi->base + SPILVL);
else else
iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL); iowrite32(SPI_INTLVL_0, dspi->base + SPILVL);
ret = spi_bitbang_start(&davinci_spi->bitbang); iowrite32(CS_DEFAULT, dspi->base + SPIDEF);
if (ret)
goto free_clk;
dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base); /* master mode default */
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_CLKMOD_MASK);
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_MASTER_MASK);
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
ret = spi_bitbang_start(&dspi->bitbang);
if (ret)
goto free_dma;
if (!pdata->poll_mode) dev_info(&pdev->dev, "Controller at 0x%p\n", dspi->base);
dev_info(&pdev->dev, "Operating in interrupt mode"
" using IRQ %d\n", davinci_spi->irq);
return ret; return ret;
free_dma:
edma_free_channel(dspi->dma.tx_channel);
edma_free_channel(dspi->dma.rx_channel);
edma_free_slot(dspi->dma.dummy_param_slot);
free_clk: free_clk:
clk_disable(davinci_spi->clk); clk_disable(dspi->clk);
clk_put(davinci_spi->clk); clk_put(dspi->clk);
put_master: put_master:
spi_master_put(master); spi_master_put(master);
free_tmp_buf:
kfree(davinci_spi->tmp_buf);
irq_free: irq_free:
free_irq(davinci_spi->irq, davinci_spi); free_irq(dspi->irq, dspi);
unmap_io: unmap_io:
iounmap(davinci_spi->base); iounmap(dspi->base);
release_region: release_region:
release_mem_region(davinci_spi->pbase, davinci_spi->region_size); release_mem_region(dspi->pbase, resource_size(r));
free_master: free_master:
kfree(master); kfree(master);
err: err:
...@@ -1222,27 +974,31 @@ static int davinci_spi_probe(struct platform_device *pdev) ...@@ -1222,27 +974,31 @@ static int davinci_spi_probe(struct platform_device *pdev)
*/ */
static int __exit davinci_spi_remove(struct platform_device *pdev) static int __exit davinci_spi_remove(struct platform_device *pdev)
{ {
struct davinci_spi *davinci_spi; struct davinci_spi *dspi;
struct spi_master *master; struct spi_master *master;
struct resource *r;
master = dev_get_drvdata(&pdev->dev); master = dev_get_drvdata(&pdev->dev);
davinci_spi = spi_master_get_devdata(master); dspi = spi_master_get_devdata(master);
spi_bitbang_stop(&davinci_spi->bitbang); spi_bitbang_stop(&dspi->bitbang);
clk_disable(davinci_spi->clk); clk_disable(dspi->clk);
clk_put(davinci_spi->clk); clk_put(dspi->clk);
spi_master_put(master); spi_master_put(master);
kfree(davinci_spi->tmp_buf); free_irq(dspi->irq, dspi);
free_irq(davinci_spi->irq, davinci_spi); iounmap(dspi->base);
iounmap(davinci_spi->base); r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(davinci_spi->pbase, davinci_spi->region_size); release_mem_region(dspi->pbase, resource_size(r));
return 0; return 0;
} }
static struct platform_driver davinci_spi_driver = { static struct platform_driver davinci_spi_driver = {
.driver.name = "spi_davinci", .driver = {
.name = "spi_davinci",
.owner = THIS_MODULE,
},
.remove = __exit_p(davinci_spi_remove), .remove = __exit_p(davinci_spi_remove),
}; };
......
...@@ -164,20 +164,23 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws) ...@@ -164,20 +164,23 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
static void wait_till_not_busy(struct dw_spi *dws) static void wait_till_not_busy(struct dw_spi *dws)
{ {
unsigned long end = jiffies + 1 + usecs_to_jiffies(1000); unsigned long end = jiffies + 1 + usecs_to_jiffies(5000);
while (time_before(jiffies, end)) { while (time_before(jiffies, end)) {
if (!(dw_readw(dws, sr) & SR_BUSY)) if (!(dw_readw(dws, sr) & SR_BUSY))
return; return;
cpu_relax();
} }
dev_err(&dws->master->dev, dev_err(&dws->master->dev,
"DW SPI: Status keeps busy for 1000us after a read/write!\n"); "DW SPI: Status keeps busy for 5000us after a read/write!\n");
} }
static void flush(struct dw_spi *dws) static void flush(struct dw_spi *dws)
{ {
while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) {
dw_readw(dws, dr); dw_readw(dws, dr);
cpu_relax();
}
wait_till_not_busy(dws); wait_till_not_busy(dws);
} }
...@@ -285,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws) ...@@ -285,8 +288,10 @@ static void *next_transfer(struct dw_spi *dws)
*/ */
static int map_dma_buffers(struct dw_spi *dws) static int map_dma_buffers(struct dw_spi *dws)
{ {
if (!dws->cur_msg->is_dma_mapped || !dws->dma_inited if (!dws->cur_msg->is_dma_mapped
|| !dws->cur_chip->enable_dma) || !dws->dma_inited
|| !dws->cur_chip->enable_dma
|| !dws->dma_ops)
return 0; return 0;
if (dws->cur_transfer->tx_dma) if (dws->cur_transfer->tx_dma)
...@@ -338,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg) ...@@ -338,7 +343,7 @@ static void int_error_stop(struct dw_spi *dws, const char *msg)
tasklet_schedule(&dws->pump_transfers); tasklet_schedule(&dws->pump_transfers);
} }
static void transfer_complete(struct dw_spi *dws) void dw_spi_xfer_done(struct dw_spi *dws)
{ {
/* Update total byte transfered return count actual bytes read */ /* Update total byte transfered return count actual bytes read */
dws->cur_msg->actual_length += dws->len; dws->cur_msg->actual_length += dws->len;
...@@ -353,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws) ...@@ -353,6 +358,7 @@ static void transfer_complete(struct dw_spi *dws)
} else } else
tasklet_schedule(&dws->pump_transfers); tasklet_schedule(&dws->pump_transfers);
} }
EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
static irqreturn_t interrupt_transfer(struct dw_spi *dws) static irqreturn_t interrupt_transfer(struct dw_spi *dws)
{ {
...@@ -384,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws) ...@@ -384,7 +390,7 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
if (dws->tx_end > dws->tx) if (dws->tx_end > dws->tx)
spi_umask_intr(dws, SPI_INT_TXEI); spi_umask_intr(dws, SPI_INT_TXEI);
else else
transfer_complete(dws); dw_spi_xfer_done(dws);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -419,11 +425,7 @@ static void poll_transfer(struct dw_spi *dws) ...@@ -419,11 +425,7 @@ static void poll_transfer(struct dw_spi *dws)
*/ */
dws->read(dws); dws->read(dws);
transfer_complete(dws); dw_spi_xfer_done(dws);
}
static void dma_transfer(struct dw_spi *dws, int cs_change)
{
} }
static void pump_transfers(unsigned long data) static void pump_transfers(unsigned long data)
...@@ -592,7 +594,7 @@ static void pump_transfers(unsigned long data) ...@@ -592,7 +594,7 @@ static void pump_transfers(unsigned long data)
spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); spi_set_clk(dws, clk_div ? clk_div : chip->clk_div);
spi_chip_sel(dws, spi->chip_select); spi_chip_sel(dws, spi->chip_select);
/* Set the interrupt mask, for poll mode just diable all int */ /* Set the interrupt mask, for poll mode just disable all int */
spi_mask_intr(dws, 0xff); spi_mask_intr(dws, 0xff);
if (imask) if (imask)
spi_umask_intr(dws, imask); spi_umask_intr(dws, imask);
...@@ -605,7 +607,7 @@ static void pump_transfers(unsigned long data) ...@@ -605,7 +607,7 @@ static void pump_transfers(unsigned long data)
} }
if (dws->dma_mapped) if (dws->dma_mapped)
dma_transfer(dws, cs_change); dws->dma_ops->dma_transfer(dws, cs_change);
if (chip->poll_mode) if (chip->poll_mode)
poll_transfer(dws); poll_transfer(dws);
...@@ -901,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws) ...@@ -901,11 +903,17 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
master->setup = dw_spi_setup; master->setup = dw_spi_setup;
master->transfer = dw_spi_transfer; master->transfer = dw_spi_transfer;
dws->dma_inited = 0;
/* Basic HW init */ /* Basic HW init */
spi_hw_init(dws); spi_hw_init(dws);
if (dws->dma_ops && dws->dma_ops->dma_init) {
ret = dws->dma_ops->dma_init(dws);
if (ret) {
dev_warn(&master->dev, "DMA init failed\n");
dws->dma_inited = 0;
}
}
/* Initial and start queue */ /* Initial and start queue */
ret = init_queue(dws); ret = init_queue(dws);
if (ret) { if (ret) {
...@@ -930,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws) ...@@ -930,6 +938,8 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
err_queue_alloc: err_queue_alloc:
destroy_queue(dws); destroy_queue(dws);
if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws);
err_diable_hw: err_diable_hw:
spi_enable_chip(dws, 0); spi_enable_chip(dws, 0);
free_irq(dws->irq, dws); free_irq(dws->irq, dws);
...@@ -938,7 +948,7 @@ int __devinit dw_spi_add_host(struct dw_spi *dws) ...@@ -938,7 +948,7 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
exit: exit:
return ret; return ret;
} }
EXPORT_SYMBOL(dw_spi_add_host); EXPORT_SYMBOL_GPL(dw_spi_add_host);
void __devexit dw_spi_remove_host(struct dw_spi *dws) void __devexit dw_spi_remove_host(struct dw_spi *dws)
{ {
...@@ -954,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws) ...@@ -954,6 +964,8 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not " dev_err(&dws->master->dev, "dw_spi_remove: workqueue will not "
"complete, message memory not freed\n"); "complete, message memory not freed\n");
if (dws->dma_ops && dws->dma_ops->dma_exit)
dws->dma_ops->dma_exit(dws);
spi_enable_chip(dws, 0); spi_enable_chip(dws, 0);
/* Disable clk */ /* Disable clk */
spi_set_clk(dws, 0); spi_set_clk(dws, 0);
...@@ -962,7 +974,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws) ...@@ -962,7 +974,7 @@ void __devexit dw_spi_remove_host(struct dw_spi *dws)
/* Disconnect from the SPI framework */ /* Disconnect from the SPI framework */
spi_unregister_master(dws->master); spi_unregister_master(dws->master);
} }
EXPORT_SYMBOL(dw_spi_remove_host); EXPORT_SYMBOL_GPL(dw_spi_remove_host);
int dw_spi_suspend_host(struct dw_spi *dws) int dw_spi_suspend_host(struct dw_spi *dws)
{ {
...@@ -975,7 +987,7 @@ int dw_spi_suspend_host(struct dw_spi *dws) ...@@ -975,7 +987,7 @@ int dw_spi_suspend_host(struct dw_spi *dws)
spi_set_clk(dws, 0); spi_set_clk(dws, 0);
return ret; return ret;
} }
EXPORT_SYMBOL(dw_spi_suspend_host); EXPORT_SYMBOL_GPL(dw_spi_suspend_host);
int dw_spi_resume_host(struct dw_spi *dws) int dw_spi_resume_host(struct dw_spi *dws)
{ {
...@@ -987,7 +999,7 @@ int dw_spi_resume_host(struct dw_spi *dws) ...@@ -987,7 +999,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
return ret; return ret;
} }
EXPORT_SYMBOL(dw_spi_resume_host); EXPORT_SYMBOL_GPL(dw_spi_resume_host);
MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>"); MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
MODULE_DESCRIPTION("Driver for DesignWare SPI controller core"); MODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
......
/*
* dw_spi_mid.c - special handling for DW core on Intel MID platform
*
* Copyright (c) 2009, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/dw_spi.h>
#ifdef CONFIG_SPI_DW_MID_DMA
#include <linux/intel_mid_dma.h>
#include <linux/pci.h>
struct mid_dma {
struct intel_mid_dma_slave dmas_tx;
struct intel_mid_dma_slave dmas_rx;
};
static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{
struct dw_spi *dws = param;
return dws->dmac && (&dws->dmac->dev == chan->device->dev);
}
static int mid_spi_dma_init(struct dw_spi *dws)
{
struct mid_dma *dw_dma = dws->dma_priv;
struct intel_mid_dma_slave *rxs, *txs;
dma_cap_mask_t mask;
/*
* Get pci device for DMA controller, currently it could only
* be the DMA controller of either Moorestown or Medfield
*/
dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL);
if (!dws->dmac)
dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
/* 1. Init rx channel */
dws->rxchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
if (!dws->rxchan)
goto err_exit;
rxs = &dw_dma->dmas_rx;
rxs->hs_mode = LNW_DMA_HW_HS;
rxs->cfg_mode = LNW_DMA_PER_TO_MEM;
dws->rxchan->private = rxs;
/* 2. Init tx channel */
dws->txchan = dma_request_channel(mask, mid_spi_dma_chan_filter, dws);
if (!dws->txchan)
goto free_rxchan;
txs = &dw_dma->dmas_tx;
txs->hs_mode = LNW_DMA_HW_HS;
txs->cfg_mode = LNW_DMA_MEM_TO_PER;
dws->txchan->private = txs;
dws->dma_inited = 1;
return 0;
free_rxchan:
dma_release_channel(dws->rxchan);
err_exit:
return -1;
}
static void mid_spi_dma_exit(struct dw_spi *dws)
{
dma_release_channel(dws->txchan);
dma_release_channel(dws->rxchan);
}
/*
* dws->dma_chan_done is cleared before the dma transfer starts,
* callback for rx/tx channel will each increment it by 1.
* Reaching 2 means the whole spi transaction is done.
*/
static void dw_spi_dma_done(void *arg)
{
struct dw_spi *dws = arg;
if (++dws->dma_chan_done != 2)
return;
dw_spi_xfer_done(dws);
}
static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
{
struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
struct dma_chan *txchan, *rxchan;
struct dma_slave_config txconf, rxconf;
u16 dma_ctrl = 0;
/* 1. setup DMA related registers */
if (cs_change) {
spi_enable_chip(dws, 0);
dw_writew(dws, dmardlr, 0xf);
dw_writew(dws, dmatdlr, 0x10);
if (dws->tx_dma)
dma_ctrl |= 0x2;
if (dws->rx_dma)
dma_ctrl |= 0x1;
dw_writew(dws, dmacr, dma_ctrl);
spi_enable_chip(dws, 1);
}
dws->dma_chan_done = 0;
txchan = dws->txchan;
rxchan = dws->rxchan;
/* 2. Prepare the TX dma transfer */
txconf.direction = DMA_TO_DEVICE;
txconf.dst_addr = dws->dma_addr;
txconf.dst_maxburst = LNW_DMA_MSIZE_16;
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
(unsigned long) &txconf);
memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
dws->tx_sgl.dma_address = dws->tx_dma;
dws->tx_sgl.length = dws->len;
txdesc = txchan->device->device_prep_slave_sg(txchan,
&dws->tx_sgl,
1,
DMA_TO_DEVICE,
DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
txdesc->callback = dw_spi_dma_done;
txdesc->callback_param = dws;
/* 3. Prepare the RX dma transfer */
rxconf.direction = DMA_FROM_DEVICE;
rxconf.src_addr = dws->dma_addr;
rxconf.src_maxburst = LNW_DMA_MSIZE_16;
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
(unsigned long) &rxconf);
memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
dws->rx_sgl.dma_address = dws->rx_dma;
dws->rx_sgl.length = dws->len;
rxdesc = rxchan->device->device_prep_slave_sg(rxchan,
&dws->rx_sgl,
1,
DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_DEST_UNMAP);
rxdesc->callback = dw_spi_dma_done;
rxdesc->callback_param = dws;
/* rx must be started before tx due to spi instinct */
rxdesc->tx_submit(rxdesc);
txdesc->tx_submit(txdesc);
return 0;
}
static struct dw_spi_dma_ops mid_dma_ops = {
.dma_init = mid_spi_dma_init,
.dma_exit = mid_spi_dma_exit,
.dma_transfer = mid_spi_dma_transfer,
};
#endif
/* Some specific info for SPI0 controller on Moorestown */
/* HW info for MRST CLk Control Unit, one 32b reg */
#define MRST_SPI_CLK_BASE 100000000 /* 100m */
#define MRST_CLK_SPI0_REG 0xff11d86c
#define CLK_SPI_BDIV_OFFSET 0
#define CLK_SPI_BDIV_MASK 0x00000007
#define CLK_SPI_CDIV_OFFSET 9
#define CLK_SPI_CDIV_MASK 0x00000e00
#define CLK_SPI_DISABLE_OFFSET 8
int dw_spi_mid_init(struct dw_spi *dws)
{
u32 *clk_reg, clk_cdiv;
clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16);
if (!clk_reg)
return -ENOMEM;
/* get SPI controller operating freq info */
clk_cdiv = (readl(clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET;
dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1);
iounmap(clk_reg);
dws->num_cs = 16;
dws->fifo_len = 40; /* FIFO has 40 words buffer */
#ifdef CONFIG_SPI_DW_MID_DMA
dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL);
if (!dws->dma_priv)
return -ENOMEM;
dws->dma_ops = &mid_dma_ops;
#endif
return 0;
}
/* /*
* mrst_spi_pci.c - PCI interface driver for DW SPI Core * dw_spi_pci.c - PCI interface driver for DW SPI Core
* *
* Copyright (c) 2009, Intel Corporation. * Copyright (c) 2009, Intel Corporation.
* *
...@@ -72,9 +72,17 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev, ...@@ -72,9 +72,17 @@ static int __devinit spi_pci_probe(struct pci_dev *pdev,
dws->parent_dev = &pdev->dev; dws->parent_dev = &pdev->dev;
dws->bus_num = 0; dws->bus_num = 0;
dws->num_cs = 4; dws->num_cs = 4;
dws->max_freq = 25000000; /* for Moorestwon */
dws->irq = pdev->irq; dws->irq = pdev->irq;
dws->fifo_len = 40; /* FIFO has 40 words buffer */
/*
* Specific handling for Intel MID paltforms, like dma setup,
* clock rate, FIFO depth.
*/
if (pdev->device == 0x0800) {
ret = dw_spi_mid_init(dws);
if (ret)
goto err_unmap;
}
ret = dw_spi_add_host(dws); ret = dw_spi_add_host(dws);
if (ret) if (ret)
...@@ -140,7 +148,7 @@ static int spi_resume(struct pci_dev *pdev) ...@@ -140,7 +148,7 @@ static int spi_resume(struct pci_dev *pdev)
#endif #endif
static const struct pci_device_id pci_ids[] __devinitdata = { static const struct pci_device_id pci_ids[] __devinitdata = {
/* Intel Moorestown platform SPI controller 0 */ /* Intel MID platform SPI controller 0 */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0800) },
{}, {},
}; };
......
...@@ -363,7 +363,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id) ...@@ -363,7 +363,7 @@ static irqreturn_t mpc52xx_psc_spi_isr(int irq, void *dev_id)
} }
/* bus_num is used only for the case dev->platform_data == NULL */ /* bus_num is used only for the case dev->platform_data == NULL */
static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, static int __devinit mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
u32 size, unsigned int irq, s16 bus_num) u32 size, unsigned int irq, s16 bus_num)
{ {
struct fsl_spi_platform_data *pdata = dev->platform_data; struct fsl_spi_platform_data *pdata = dev->platform_data;
...@@ -450,22 +450,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr, ...@@ -450,22 +450,7 @@ static int __init mpc52xx_psc_spi_do_probe(struct device *dev, u32 regaddr,
return ret; return ret;
} }
static int __exit mpc52xx_psc_spi_do_remove(struct device *dev) static int __devinit mpc52xx_psc_spi_of_probe(struct platform_device *op,
{
struct spi_master *master = dev_get_drvdata(dev);
struct mpc52xx_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 mpc52xx_psc_spi_of_probe(struct platform_device *op,
const struct of_device_id *match) const struct of_device_id *match)
{ {
const u32 *regaddr_p; const u32 *regaddr_p;
...@@ -495,9 +480,19 @@ static int __init mpc52xx_psc_spi_of_probe(struct platform_device *op, ...@@ -495,9 +480,19 @@ static int __init mpc52xx_psc_spi_of_probe(struct platform_device *op,
irq_of_parse_and_map(op->dev.of_node, 0), id); irq_of_parse_and_map(op->dev.of_node, 0), id);
} }
static int __exit mpc52xx_psc_spi_of_remove(struct platform_device *op) static int __devexit mpc52xx_psc_spi_of_remove(struct platform_device *op)
{ {
return mpc52xx_psc_spi_do_remove(&op->dev); struct spi_master *master = dev_get_drvdata(&op->dev);
struct mpc52xx_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 const struct of_device_id mpc52xx_psc_spi_of_match[] = { static const struct of_device_id mpc52xx_psc_spi_of_match[] = {
...@@ -510,7 +505,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match); ...@@ -510,7 +505,7 @@ MODULE_DEVICE_TABLE(of, mpc52xx_psc_spi_of_match);
static struct of_platform_driver mpc52xx_psc_spi_of_driver = { static struct of_platform_driver mpc52xx_psc_spi_of_driver = {
.probe = mpc52xx_psc_spi_of_probe, .probe = mpc52xx_psc_spi_of_probe,
.remove = __exit_p(mpc52xx_psc_spi_of_remove), .remove = __devexit_p(mpc52xx_psc_spi_of_remove),
.driver = { .driver = {
.name = "mpc52xx-psc-spi", .name = "mpc52xx-psc-spi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -397,7 +397,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -397,7 +397,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (tx != NULL) { if (tx != NULL) {
wait_for_completion(&mcspi_dma->dma_tx_completion); wait_for_completion(&mcspi_dma->dma_tx_completion);
dma_unmap_single(NULL, xfer->tx_dma, count, DMA_TO_DEVICE); dma_unmap_single(&spi->dev, xfer->tx_dma, count, DMA_TO_DEVICE);
/* for TX_ONLY mode, be sure all words have shifted out */ /* for TX_ONLY mode, be sure all words have shifted out */
if (rx == NULL) { if (rx == NULL) {
...@@ -412,7 +412,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) ...@@ -412,7 +412,7 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
if (rx != NULL) { if (rx != NULL) {
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(&spi->dev, 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 (l & OMAP2_MCSPI_CHCONF_TURBO) {
...@@ -1025,11 +1025,6 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) ...@@ -1025,11 +1025,6 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
if (m->is_dma_mapped || len < DMA_MIN_BYTES) if (m->is_dma_mapped || len < DMA_MIN_BYTES)
continue; continue;
/* Do DMA mapping "early" for better error reporting and
* dcache use. Note that if dma_unmap_single() ever starts
* to do real work on ARM, we'd need to clean up mappings
* for previous transfers on *ALL* exits of this loop...
*/
if (tx_buf != NULL) { if (tx_buf != NULL) {
t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf, t->tx_dma = dma_map_single(&spi->dev, (void *) tx_buf,
len, DMA_TO_DEVICE); len, DMA_TO_DEVICE);
...@@ -1046,7 +1041,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m) ...@@ -1046,7 +1041,7 @@ static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
dev_dbg(&spi->dev, "dma %cX %d bytes error\n", dev_dbg(&spi->dev, "dma %cX %d bytes error\n",
'R', len); 'R', len);
if (tx_buf != NULL) if (tx_buf != NULL)
dma_unmap_single(NULL, t->tx_dma, dma_unmap_single(&spi->dev, t->tx_dma,
len, DMA_TO_DEVICE); len, DMA_TO_DEVICE);
return -EINVAL; return -EINVAL;
} }
......
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/clk.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -35,9 +35,6 @@ ...@@ -35,9 +35,6 @@
#include <asm/irq.h> #include <asm/irq.h>
#include <asm/delay.h> #include <asm/delay.h>
#include <mach/dma.h>
#include <plat/ssp.h>
#include <mach/pxa2xx_spi.h>
MODULE_AUTHOR("Stephen Street"); MODULE_AUTHOR("Stephen Street");
MODULE_DESCRIPTION("PXA2xx SSP SPI Controller"); MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
...@@ -46,8 +43,6 @@ MODULE_ALIAS("platform:pxa2xx-spi"); ...@@ -46,8 +43,6 @@ MODULE_ALIAS("platform:pxa2xx-spi");
#define MAX_BUSES 3 #define MAX_BUSES 3
#define RX_THRESH_DFLT 8
#define TX_THRESH_DFLT 8
#define TIMOUT_DFLT 1000 #define TIMOUT_DFLT 1000
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR) #define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
...@@ -168,7 +163,10 @@ struct chip_data { ...@@ -168,7 +163,10 @@ struct chip_data {
u8 enable_dma; u8 enable_dma;
u8 bits_per_word; u8 bits_per_word;
u32 speed_hz; u32 speed_hz;
union {
int gpio_cs; int gpio_cs;
unsigned int frm;
};
int gpio_cs_inverted; int gpio_cs_inverted;
int (*write)(struct driver_data *drv_data); int (*write)(struct driver_data *drv_data);
int (*read)(struct driver_data *drv_data); int (*read)(struct driver_data *drv_data);
...@@ -181,6 +179,11 @@ static void cs_assert(struct driver_data *drv_data) ...@@ -181,6 +179,11 @@ static void cs_assert(struct driver_data *drv_data)
{ {
struct chip_data *chip = drv_data->cur_chip; struct chip_data *chip = drv_data->cur_chip;
if (drv_data->ssp_type == CE4100_SSP) {
write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
return;
}
if (chip->cs_control) { if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_ASSERT); chip->cs_control(PXA2XX_CS_ASSERT);
return; return;
...@@ -194,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data) ...@@ -194,6 +197,9 @@ static void cs_deassert(struct driver_data *drv_data)
{ {
struct chip_data *chip = drv_data->cur_chip; struct chip_data *chip = drv_data->cur_chip;
if (drv_data->ssp_type == CE4100_SSP)
return;
if (chip->cs_control) { if (chip->cs_control) {
chip->cs_control(PXA2XX_CS_DEASSERT); chip->cs_control(PXA2XX_CS_DEASSERT);
return; return;
...@@ -203,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data) ...@@ -203,6 +209,25 @@ static void cs_deassert(struct driver_data *drv_data)
gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted); gpio_set_value(chip->gpio_cs, !chip->gpio_cs_inverted);
} }
static void write_SSSR_CS(struct driver_data *drv_data, u32 val)
{
void __iomem *reg = drv_data->ioaddr;
if (drv_data->ssp_type == CE4100_SSP)
val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
write_SSSR(val, reg);
}
static int pxa25x_ssp_comp(struct driver_data *drv_data)
{
if (drv_data->ssp_type == PXA25x_SSP)
return 1;
if (drv_data->ssp_type == CE4100_SSP)
return 1;
return 0;
}
static int flush(struct driver_data *drv_data) static int flush(struct driver_data *drv_data)
{ {
unsigned long limit = loops_per_jiffy << 1; unsigned long limit = loops_per_jiffy << 1;
...@@ -214,7 +239,7 @@ static int flush(struct driver_data *drv_data) ...@@ -214,7 +239,7 @@ static int flush(struct driver_data *drv_data)
read_SSDR(reg); read_SSDR(reg);
} }
} while ((read_SSSR(reg) & SSSR_BSY) && --limit); } while ((read_SSSR(reg) & SSSR_BSY) && --limit);
write_SSSR(SSSR_ROR, reg); write_SSSR_CS(drv_data, SSSR_ROR);
return limit; return limit;
} }
...@@ -224,7 +249,7 @@ static int null_writer(struct driver_data *drv_data) ...@@ -224,7 +249,7 @@ static int null_writer(struct driver_data *drv_data)
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes; u8 n_bytes = drv_data->n_bytes;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end)) || (drv_data->tx == drv_data->tx_end))
return 0; return 0;
...@@ -252,7 +277,7 @@ static int u8_writer(struct driver_data *drv_data) ...@@ -252,7 +277,7 @@ static int u8_writer(struct driver_data *drv_data)
{ {
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end)) || (drv_data->tx == drv_data->tx_end))
return 0; return 0;
...@@ -279,7 +304,7 @@ static int u16_writer(struct driver_data *drv_data) ...@@ -279,7 +304,7 @@ static int u16_writer(struct driver_data *drv_data)
{ {
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end)) || (drv_data->tx == drv_data->tx_end))
return 0; return 0;
...@@ -306,7 +331,7 @@ static int u32_writer(struct driver_data *drv_data) ...@@ -306,7 +331,7 @@ static int u32_writer(struct driver_data *drv_data)
{ {
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
if (((read_SSSR(reg) & 0x00000f00) == 0x00000f00) if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
|| (drv_data->tx == drv_data->tx_end)) || (drv_data->tx == drv_data->tx_end))
return 0; return 0;
...@@ -507,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg) ...@@ -507,9 +532,9 @@ static void dma_error_stop(struct driver_data *drv_data, const char *msg)
/* Stop and reset */ /* Stop and reset */
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
write_SSSR(drv_data->clear_sr, reg); write_SSSR_CS(drv_data, drv_data->clear_sr);
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg); write_SSTO(0, reg);
flush(drv_data); flush(drv_data);
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
...@@ -529,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data) ...@@ -529,7 +554,7 @@ static void dma_transfer_complete(struct driver_data *drv_data)
/* Clear and disable interrupts on SSP and DMA channels*/ /* Clear and disable interrupts on SSP and DMA channels*/
write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg); write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
write_SSSR(drv_data->clear_sr, reg); write_SSSR_CS(drv_data, drv_data->clear_sr);
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL; DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
...@@ -622,7 +647,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) ...@@ -622,7 +647,7 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
/* Clear and disable timeout interrupt, do the rest in /* Clear and disable timeout interrupt, do the rest in
* dma_transfer_complete */ * dma_transfer_complete */
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg); write_SSTO(0, reg);
/* finish this transfer, start the next */ /* finish this transfer, start the next */
...@@ -635,14 +660,26 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data) ...@@ -635,14 +660,26 @@ static irqreturn_t dma_transfer(struct driver_data *drv_data)
return IRQ_NONE; return IRQ_NONE;
} }
static void reset_sccr1(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
struct chip_data *chip = drv_data->cur_chip;
u32 sccr1_reg;
sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
sccr1_reg &= ~SSCR1_RFT;
sccr1_reg |= chip->threshold;
write_SSCR1(sccr1_reg, reg);
}
static void int_error_stop(struct driver_data *drv_data, const char* msg) static void int_error_stop(struct driver_data *drv_data, const char* msg)
{ {
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
/* Stop and reset SSP */ /* Stop and reset SSP */
write_SSSR(drv_data->clear_sr, reg); write_SSSR_CS(drv_data, drv_data->clear_sr);
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); reset_sccr1(drv_data);
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg); write_SSTO(0, reg);
flush(drv_data); flush(drv_data);
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
...@@ -658,9 +695,9 @@ static void int_transfer_complete(struct driver_data *drv_data) ...@@ -658,9 +695,9 @@ static void int_transfer_complete(struct driver_data *drv_data)
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
/* Stop SSP */ /* Stop SSP */
write_SSSR(drv_data->clear_sr, reg); write_SSSR_CS(drv_data, drv_data->clear_sr);
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); reset_sccr1(drv_data);
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg); write_SSTO(0, reg);
/* Update total byte transfered return count actual bytes read */ /* Update total byte transfered return count actual bytes read */
...@@ -714,24 +751,34 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) ...@@ -714,24 +751,34 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
} }
if (drv_data->tx == drv_data->tx_end) { if (drv_data->tx == drv_data->tx_end) {
write_SSCR1(read_SSCR1(reg) & ~SSCR1_TIE, reg); u32 bytes_left;
/* PXA25x_SSP has no timeout, read trailing bytes */ u32 sccr1_reg;
if (drv_data->ssp_type == PXA25x_SSP) {
if (!wait_ssp_rx_stall(reg)) sccr1_reg = read_SSCR1(reg);
{ sccr1_reg &= ~SSCR1_TIE;
int_error_stop(drv_data, "interrupt_transfer: "
"rx stall failed"); /*
return IRQ_HANDLED; * PXA25x_SSP has no timeout, set up rx threshould for the
} * remaing RX bytes.
if (!drv_data->read(drv_data)) */
{ if (pxa25x_ssp_comp(drv_data)) {
int_error_stop(drv_data,
"interrupt_transfer: " sccr1_reg &= ~SSCR1_RFT;
"trailing byte read failed");
return IRQ_HANDLED; bytes_left = drv_data->rx_end - drv_data->rx;
switch (drv_data->n_bytes) {
case 4:
bytes_left >>= 1;
case 2:
bytes_left >>= 1;
} }
int_transfer_complete(drv_data);
if (bytes_left > RX_THRESH_DFLT)
bytes_left = RX_THRESH_DFLT;
sccr1_reg |= SSCR1_RxTresh(bytes_left);
} }
write_SSCR1(sccr1_reg, reg);
} }
/* We did something */ /* We did something */
...@@ -742,14 +789,26 @@ static irqreturn_t ssp_int(int irq, void *dev_id) ...@@ -742,14 +789,26 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
{ {
struct driver_data *drv_data = dev_id; struct driver_data *drv_data = dev_id;
void __iomem *reg = drv_data->ioaddr; void __iomem *reg = drv_data->ioaddr;
u32 sccr1_reg = read_SSCR1(reg);
u32 mask = drv_data->mask_sr;
u32 status;
status = read_SSSR(reg);
/* Ignore possible writes if we don't need to write */
if (!(sccr1_reg & SSCR1_TIE))
mask &= ~SSSR_TFS;
if (!(status & mask))
return IRQ_NONE;
if (!drv_data->cur_msg) { if (!drv_data->cur_msg) {
write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg); write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg); write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, reg); write_SSTO(0, reg);
write_SSSR(drv_data->clear_sr, reg); write_SSSR_CS(drv_data, drv_data->clear_sr);
dev_err(&drv_data->pdev->dev, "bad message state " dev_err(&drv_data->pdev->dev, "bad message state "
"in interrupt handler\n"); "in interrupt handler\n");
...@@ -862,7 +921,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate) ...@@ -862,7 +921,7 @@ static unsigned int ssp_get_clk_div(struct ssp_device *ssp, int rate)
{ {
unsigned long ssp_clk = clk_get_rate(ssp->clk); unsigned long ssp_clk = clk_get_rate(ssp->clk);
if (ssp->type == PXA25x_SSP) if (ssp->type == PXA25x_SSP || ssp->type == CE4100_SSP)
return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8; return ((ssp_clk / (2 * rate) - 1) & 0xff) << 8;
else else
return ((ssp_clk / rate - 1) & 0xfff) << 8; return ((ssp_clk / rate - 1) & 0xfff) << 8;
...@@ -1088,7 +1147,7 @@ static void pump_transfers(unsigned long data) ...@@ -1088,7 +1147,7 @@ static void pump_transfers(unsigned long data)
/* Clear status */ /* Clear status */
cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1; cr1 = chip->cr1 | chip->threshold | drv_data->int_cr1;
write_SSSR(drv_data->clear_sr, reg); write_SSSR_CS(drv_data, drv_data->clear_sr);
} }
/* see if we need to reload the config registers */ /* see if we need to reload the config registers */
...@@ -1098,7 +1157,7 @@ static void pump_transfers(unsigned long data) ...@@ -1098,7 +1157,7 @@ static void pump_transfers(unsigned long data)
/* stop the SSP, and update the other bits */ /* stop the SSP, and update the other bits */
write_SSCR0(cr0 & ~SSCR0_SSE, reg); write_SSCR0(cr0 & ~SSCR0_SSE, reg);
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(chip->timeout, reg); write_SSTO(chip->timeout, reg);
/* first set CR1 without interrupt and service enables */ /* first set CR1 without interrupt and service enables */
write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg); write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
...@@ -1106,7 +1165,7 @@ static void pump_transfers(unsigned long data) ...@@ -1106,7 +1165,7 @@ static void pump_transfers(unsigned long data)
write_SSCR0(cr0, reg); write_SSCR0(cr0, reg);
} else { } else {
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(chip->timeout, reg); write_SSTO(chip->timeout, reg);
} }
...@@ -1233,14 +1292,13 @@ static int setup(struct spi_device *spi) ...@@ -1233,14 +1292,13 @@ static int setup(struct spi_device *spi)
uint tx_thres = TX_THRESH_DFLT; uint tx_thres = TX_THRESH_DFLT;
uint rx_thres = RX_THRESH_DFLT; uint rx_thres = RX_THRESH_DFLT;
if (drv_data->ssp_type != PXA25x_SSP if (!pxa25x_ssp_comp(drv_data)
&& (spi->bits_per_word < 4 || spi->bits_per_word > 32)) { && (spi->bits_per_word < 4 || spi->bits_per_word > 32)) {
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d " dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
"b/w not 4-32 for type non-PXA25x_SSP\n", "b/w not 4-32 for type non-PXA25x_SSP\n",
drv_data->ssp_type, spi->bits_per_word); drv_data->ssp_type, spi->bits_per_word);
return -EINVAL; return -EINVAL;
} } else if (pxa25x_ssp_comp(drv_data)
else if (drv_data->ssp_type == PXA25x_SSP
&& (spi->bits_per_word < 4 && (spi->bits_per_word < 4
|| spi->bits_per_word > 16)) { || spi->bits_per_word > 16)) {
dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d " dev_err(&spi->dev, "failed setup: ssp_type=%d, bits/wrd=%d "
...@@ -1259,6 +1317,16 @@ static int setup(struct spi_device *spi) ...@@ -1259,6 +1317,16 @@ static int setup(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
} }
if (drv_data->ssp_type == CE4100_SSP) {
if (spi->chip_select > 4) {
dev_err(&spi->dev, "failed setup: "
"cs number must not be > 4.\n");
kfree(chip);
return -EINVAL;
}
chip->frm = spi->chip_select;
} else
chip->gpio_cs = -1; chip->gpio_cs = -1;
chip->enable_dma = 0; chip->enable_dma = 0;
chip->timeout = TIMOUT_DFLT; chip->timeout = TIMOUT_DFLT;
...@@ -1315,7 +1383,7 @@ static int setup(struct spi_device *spi) ...@@ -1315,7 +1383,7 @@ static int setup(struct spi_device *spi)
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0); | (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
/* NOTE: PXA25x_SSP _could_ use external clocking ... */ /* NOTE: PXA25x_SSP _could_ use external clocking ... */
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
dev_dbg(&spi->dev, "%ld Hz actual, %s\n", dev_dbg(&spi->dev, "%ld Hz actual, %s\n",
clk_get_rate(ssp->clk) clk_get_rate(ssp->clk)
/ (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)), / (1 + ((chip->cr0 & SSCR0_SCR(0xfff)) >> 8)),
...@@ -1350,23 +1418,27 @@ static int setup(struct spi_device *spi) ...@@ -1350,23 +1418,27 @@ static int setup(struct spi_device *spi)
spi_set_ctldata(spi, chip); spi_set_ctldata(spi, chip);
if (drv_data->ssp_type == CE4100_SSP)
return 0;
return setup_cs(spi, chip, chip_info); return setup_cs(spi, chip, chip_info);
} }
static void cleanup(struct spi_device *spi) static void cleanup(struct spi_device *spi)
{ {
struct chip_data *chip = spi_get_ctldata(spi); struct chip_data *chip = spi_get_ctldata(spi);
struct driver_data *drv_data = spi_master_get_devdata(spi->master);
if (!chip) if (!chip)
return; return;
if (gpio_is_valid(chip->gpio_cs)) if (drv_data->ssp_type != CE4100_SSP && gpio_is_valid(chip->gpio_cs))
gpio_free(chip->gpio_cs); gpio_free(chip->gpio_cs);
kfree(chip); kfree(chip);
} }
static int __init init_queue(struct driver_data *drv_data) static int __devinit init_queue(struct driver_data *drv_data)
{ {
INIT_LIST_HEAD(&drv_data->queue); INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock); spin_lock_init(&drv_data->lock);
...@@ -1454,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data) ...@@ -1454,7 +1526,7 @@ static int destroy_queue(struct driver_data *drv_data)
return 0; return 0;
} }
static int __init pxa2xx_spi_probe(struct platform_device *pdev) static int __devinit pxa2xx_spi_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct pxa2xx_spi_master *platform_info; struct pxa2xx_spi_master *platform_info;
...@@ -1484,6 +1556,10 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1484,6 +1556,10 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->pdev = pdev; drv_data->pdev = pdev;
drv_data->ssp = ssp; drv_data->ssp = ssp;
master->dev.parent = &pdev->dev;
#ifdef CONFIG_OF
master->dev.of_node = pdev->dev.of_node;
#endif
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
...@@ -1500,7 +1576,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1500,7 +1576,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->ioaddr = ssp->mmio_base; drv_data->ioaddr = ssp->mmio_base;
drv_data->ssdr_physical = ssp->phys_base + SSDR; drv_data->ssdr_physical = ssp->phys_base + SSDR;
if (ssp->type == PXA25x_SSP) { if (pxa25x_ssp_comp(drv_data)) {
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE; drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
drv_data->dma_cr1 = 0; drv_data->dma_cr1 = 0;
drv_data->clear_sr = SSSR_ROR; drv_data->clear_sr = SSSR_ROR;
...@@ -1512,7 +1588,8 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1512,7 +1588,8 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR; drv_data->mask_sr = SSSR_TINT | SSSR_RFS | SSSR_TFS | SSSR_ROR;
} }
status = request_irq(ssp->irq, ssp_int, 0, dev_name(dev), drv_data); status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
drv_data);
if (status < 0) { if (status < 0) {
dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq); dev_err(&pdev->dev, "cannot get IRQ %d\n", ssp->irq);
goto out_error_master_alloc; goto out_error_master_alloc;
...@@ -1561,7 +1638,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev) ...@@ -1561,7 +1638,7 @@ static int __init pxa2xx_spi_probe(struct platform_device *pdev)
| SSCR0_Motorola | SSCR0_Motorola
| SSCR0_DataSize(8), | SSCR0_DataSize(8),
drv_data->ioaddr); drv_data->ioaddr);
if (drv_data->ssp_type != PXA25x_SSP) if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, drv_data->ioaddr); write_SSTO(0, drv_data->ioaddr);
write_SSPSP(0, drv_data->ioaddr); write_SSPSP(0, drv_data->ioaddr);
...@@ -1723,13 +1800,14 @@ static struct platform_driver driver = { ...@@ -1723,13 +1800,14 @@ static struct platform_driver driver = {
.pm = &pxa2xx_spi_pm_ops, .pm = &pxa2xx_spi_pm_ops,
#endif #endif
}, },
.probe = pxa2xx_spi_probe,
.remove = pxa2xx_spi_remove, .remove = pxa2xx_spi_remove,
.shutdown = pxa2xx_spi_shutdown, .shutdown = pxa2xx_spi_shutdown,
}; };
static int __init pxa2xx_spi_init(void) static int __init pxa2xx_spi_init(void)
{ {
return platform_driver_probe(&driver, pxa2xx_spi_probe); return platform_driver_register(&driver);
} }
subsys_initcall(pxa2xx_spi_init); subsys_initcall(pxa2xx_spi_init);
......
/*
* CE4100's SPI device is more or less the same one as found on PXA
*
*/
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/spi/pxa2xx_spi.h>
struct awesome_struct {
struct ssp_device ssp;
struct platform_device spi_pdev;
struct pxa2xx_spi_master spi_pdata;
};
static DEFINE_MUTEX(ssp_lock);
static LIST_HEAD(ssp_list);
struct ssp_device *pxa_ssp_request(int port, const char *label)
{
struct ssp_device *ssp = NULL;
mutex_lock(&ssp_lock);
list_for_each_entry(ssp, &ssp_list, node) {
if (ssp->port_id == port && ssp->use_count == 0) {
ssp->use_count++;
ssp->label = label;
break;
}
}
mutex_unlock(&ssp_lock);
if (&ssp->node == &ssp_list)
return NULL;
return ssp;
}
EXPORT_SYMBOL_GPL(pxa_ssp_request);
void pxa_ssp_free(struct ssp_device *ssp)
{
mutex_lock(&ssp_lock);
if (ssp->use_count) {
ssp->use_count--;
ssp->label = NULL;
} else
dev_err(&ssp->pdev->dev, "device already free\n");
mutex_unlock(&ssp_lock);
}
EXPORT_SYMBOL_GPL(pxa_ssp_free);
static void plat_dev_release(struct device *dev)
{
struct awesome_struct *as = container_of(dev,
struct awesome_struct, spi_pdev.dev);
of_device_node_put(&as->spi_pdev.dev);
}
static int __devinit ce4100_spi_probe(struct pci_dev *dev,
const struct pci_device_id *ent)
{
int ret;
resource_size_t phys_beg;
resource_size_t phys_len;
struct awesome_struct *spi_info;
struct platform_device *pdev;
struct pxa2xx_spi_master *spi_pdata;
struct ssp_device *ssp;
ret = pci_enable_device(dev);
if (ret)
return ret;
phys_beg = pci_resource_start(dev, 0);
phys_len = pci_resource_len(dev, 0);
if (!request_mem_region(phys_beg, phys_len,
"CE4100 SPI")) {
dev_err(&dev->dev, "Can't request register space.\n");
ret = -EBUSY;
return ret;
}
spi_info = kzalloc(sizeof(*spi_info), GFP_KERNEL);
if (!spi_info) {
ret = -ENOMEM;
goto err_kz;
}
ssp = &spi_info->ssp;
pdev = &spi_info->spi_pdev;
spi_pdata = &spi_info->spi_pdata;
pdev->name = "pxa2xx-spi";
pdev->id = dev->devfn;
pdev->dev.parent = &dev->dev;
pdev->dev.platform_data = &spi_info->spi_pdata;
#ifdef CONFIG_OF
pdev->dev.of_node = dev->dev.of_node;
#endif
pdev->dev.release = plat_dev_release;
spi_pdata->num_chipselect = dev->devfn;
ssp->phys_base = pci_resource_start(dev, 0);
ssp->mmio_base = ioremap(phys_beg, phys_len);
if (!ssp->mmio_base) {
dev_err(&pdev->dev, "failed to ioremap() registers\n");
ret = -EIO;
goto err_remap;
}
ssp->irq = dev->irq;
ssp->port_id = pdev->id;
ssp->type = PXA25x_SSP;
mutex_lock(&ssp_lock);
list_add(&ssp->node, &ssp_list);
mutex_unlock(&ssp_lock);
pci_set_drvdata(dev, spi_info);
ret = platform_device_register(pdev);
if (ret)
goto err_dev_add;
return ret;
err_dev_add:
pci_set_drvdata(dev, NULL);
mutex_lock(&ssp_lock);
list_del(&ssp->node);
mutex_unlock(&ssp_lock);
iounmap(ssp->mmio_base);
err_remap:
kfree(spi_info);
err_kz:
release_mem_region(phys_beg, phys_len);
return ret;
}
static void __devexit ce4100_spi_remove(struct pci_dev *dev)
{
struct awesome_struct *spi_info;
struct platform_device *pdev;
struct ssp_device *ssp;
spi_info = pci_get_drvdata(dev);
ssp = &spi_info->ssp;
pdev = &spi_info->spi_pdev;
platform_device_unregister(pdev);
iounmap(ssp->mmio_base);
release_mem_region(pci_resource_start(dev, 0),
pci_resource_len(dev, 0));
mutex_lock(&ssp_lock);
list_del(&ssp->node);
mutex_unlock(&ssp_lock);
pci_set_drvdata(dev, NULL);
pci_disable_device(dev);
kfree(spi_info);
}
static struct pci_device_id ce4100_spi_devices[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e6a) },
{ },
};
MODULE_DEVICE_TABLE(pci, ce4100_spi_devices);
static struct pci_driver ce4100_spi_driver = {
.name = "ce4100_spi",
.id_table = ce4100_spi_devices,
.probe = ce4100_spi_probe,
.remove = __devexit_p(ce4100_spi_remove),
};
static int __init ce4100_spi_init(void)
{
return pci_register_driver(&ce4100_spi_driver);
}
module_init(ce4100_spi_init);
static void __exit ce4100_spi_exit(void)
{
pci_unregister_driver(&ce4100_spi_driver);
}
module_exit(ce4100_spi_exit);
MODULE_DESCRIPTION("CE4100 PCI-SPI glue code for PXA's driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
...@@ -66,7 +66,6 @@ enum spi_imx_devtype { ...@@ -66,7 +66,6 @@ enum spi_imx_devtype {
SPI_IMX_VER_0_5, SPI_IMX_VER_0_5,
SPI_IMX_VER_0_7, SPI_IMX_VER_0_7,
SPI_IMX_VER_2_3, SPI_IMX_VER_2_3,
SPI_IMX_VER_AUTODETECT,
}; };
struct spi_imx_data; struct spi_imx_data;
...@@ -720,9 +719,6 @@ static void spi_imx_cleanup(struct spi_device *spi) ...@@ -720,9 +719,6 @@ static void spi_imx_cleanup(struct spi_device *spi)
static struct platform_device_id spi_imx_devtype[] = { static struct platform_device_id spi_imx_devtype[] = {
{ {
.name = DRIVER_NAME,
.driver_data = SPI_IMX_VER_AUTODETECT,
}, {
.name = "imx1-cspi", .name = "imx1-cspi",
.driver_data = SPI_IMX_VER_IMX1, .driver_data = SPI_IMX_VER_IMX1,
}, { }, {
...@@ -802,31 +798,9 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) ...@@ -802,31 +798,9 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
init_completion(&spi_imx->xfer_done); init_completion(&spi_imx->xfer_done);
if (pdev->id_entry->driver_data == SPI_IMX_VER_AUTODETECT) {
if (cpu_is_mx25() || cpu_is_mx35())
spi_imx->devtype_data =
spi_imx_devtype_data[SPI_IMX_VER_0_7];
else if (cpu_is_mx25() || cpu_is_mx31() || cpu_is_mx35())
spi_imx->devtype_data =
spi_imx_devtype_data[SPI_IMX_VER_0_4];
else if (cpu_is_mx27() || cpu_is_mx21())
spi_imx->devtype_data =
spi_imx_devtype_data[SPI_IMX_VER_0_0];
else if (cpu_is_mx1())
spi_imx->devtype_data =
spi_imx_devtype_data[SPI_IMX_VER_IMX1];
else
BUG();
} else
spi_imx->devtype_data = spi_imx->devtype_data =
spi_imx_devtype_data[pdev->id_entry->driver_data]; spi_imx_devtype_data[pdev->id_entry->driver_data];
if (!spi_imx->devtype_data.intctrl) {
dev_err(&pdev->dev, "no support for this device compiled in\n");
ret = -ENODEV;
goto out_gpio_free;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) { if (!res) {
dev_err(&pdev->dev, "can't get platform resource\n"); dev_err(&pdev->dev, "can't get platform resource\n");
...@@ -847,7 +821,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev) ...@@ -847,7 +821,7 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
} }
spi_imx->irq = platform_get_irq(pdev, 0); spi_imx->irq = platform_get_irq(pdev, 0);
if (spi_imx->irq <= 0) { if (spi_imx->irq < 0) {
ret = -EINVAL; ret = -EINVAL;
goto out_iounmap; goto out_iounmap;
} }
......
...@@ -449,7 +449,7 @@ static int __devinit nuc900_spi_probe(struct platform_device *pdev) ...@@ -449,7 +449,7 @@ static int __devinit nuc900_spi_probe(struct platform_device *pdev)
release_mem_region(hw->res->start, resource_size(hw->res)); release_mem_region(hw->res->start, resource_size(hw->res));
kfree(hw->ioarea); kfree(hw->ioarea);
err_pdata: err_pdata:
spi_master_put(hw->master);; spi_master_put(hw->master);
err_nomem: err_nomem:
return err; return err;
......
...@@ -267,7 +267,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, ...@@ -267,7 +267,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val,
if (reg_spsr_val & SPSR_FI_BIT) { if (reg_spsr_val & SPSR_FI_BIT) {
/* disable FI & RFI interrupts */ /* disable FI & RFI interrupts */
pch_spi_setclr_reg(data->master, PCH_SPCR, 0, pch_spi_setclr_reg(data->master, PCH_SPCR, 0,
SPCR_FIE_BIT | SPCR_TFIE_BIT); SPCR_FIE_BIT | SPCR_RFIE_BIT);
/* transfer is completed;inform pch_spi_process_messages */ /* transfer is completed;inform pch_spi_process_messages */
data->transfer_complete = true; data->transfer_complete = true;
...@@ -677,15 +677,15 @@ static void pch_spi_set_ir(struct pch_spi_data *data) ...@@ -677,15 +677,15 @@ static void pch_spi_set_ir(struct pch_spi_data *data)
{ {
/* enable interrupts */ /* enable interrupts */
if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) { if ((data->bpw_len) > PCH_MAX_FIFO_DEPTH) {
/* set receive threhold to PCH_RX_THOLD */ /* set receive threshold to PCH_RX_THOLD */
pch_spi_setclr_reg(data->master, PCH_SPCR, pch_spi_setclr_reg(data->master, PCH_SPCR,
PCH_RX_THOLD << SPCR_TFIC_FIELD, PCH_RX_THOLD << SPCR_RFIC_FIELD,
~MASK_TFIC_SPCR_BITS); ~MASK_RFIC_SPCR_BITS);
/* enable FI and RFI interrupts */ /* enable FI and RFI interrupts */
pch_spi_setclr_reg(data->master, PCH_SPCR, pch_spi_setclr_reg(data->master, PCH_SPCR,
SPCR_RFIE_BIT | SPCR_TFIE_BIT, 0); SPCR_RFIE_BIT | SPCR_FIE_BIT, 0);
} else { } else {
/* set receive threhold to maximum */ /* set receive threshold to maximum */
pch_spi_setclr_reg(data->master, PCH_SPCR, pch_spi_setclr_reg(data->master, PCH_SPCR,
PCH_RX_THOLD_MAX << SPCR_TFIC_FIELD, PCH_RX_THOLD_MAX << SPCR_TFIC_FIELD,
~MASK_TFIC_SPCR_BITS); ~MASK_TFIC_SPCR_BITS);
......
/* /*
* xilinx_spi.c
*
* Xilinx SPI controller driver (master mode only) * Xilinx SPI controller driver (master mode only)
* *
* Author: MontaVista Software, Inc. * Author: MontaVista Software, Inc.
* source@mvista.com * source@mvista.com
* *
* 2002-2007 (c) MontaVista Software, Inc. This file is licensed under the * Copyright (c) 2010 Secret Lab Technologies, Ltd.
* terms of the GNU General Public License version 2. This program is licensed * Copyright (c) 2009 Intel Corporation
* "as is" without any warranty of any kind, whether express or implied. * 2002-2007 (c) MontaVista Software, Inc.
* 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/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h> #include <linux/spi/spi_bitbang.h>
#include <linux/io.h>
#include "xilinx_spi.h"
#include <linux/spi/xilinx_spi.h> #include <linux/spi/xilinx_spi.h>
#include <linux/io.h>
#define XILINX_SPI_NAME "xilinx_spi" #define XILINX_SPI_NAME "xilinx_spi"
...@@ -350,19 +351,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id) ...@@ -350,19 +351,22 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
#ifdef CONFIG_OF
static const struct of_device_id xilinx_spi_of_match[] = {
{ .compatible = "xlnx,xps-spi-2.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.b", },
{}
};
MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
#endif
struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
u32 irq, s16 bus_num) u32 irq, s16 bus_num, int num_cs, int little_endian, int bits_per_word)
{ {
struct spi_master *master; struct spi_master *master;
struct xilinx_spi *xspi; struct xilinx_spi *xspi;
struct xspi_platform_data *pdata = dev->platform_data;
int ret; int ret;
if (!pdata) {
dev_err(dev, "No platform data attached\n");
return NULL;
}
master = spi_alloc_master(dev, sizeof(struct xilinx_spi)); master = spi_alloc_master(dev, sizeof(struct xilinx_spi));
if (!master) if (!master)
return NULL; return NULL;
...@@ -389,21 +393,21 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem, ...@@ -389,21 +393,21 @@ struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
} }
master->bus_num = bus_num; master->bus_num = bus_num;
master->num_chipselect = pdata->num_chipselect; master->num_chipselect = num_cs;
#ifdef CONFIG_OF #ifdef CONFIG_OF
master->dev.of_node = dev->of_node; master->dev.of_node = dev->of_node;
#endif #endif
xspi->mem = *mem; xspi->mem = *mem;
xspi->irq = irq; xspi->irq = irq;
if (pdata->little_endian) { if (little_endian) {
xspi->read_fn = xspi_read32; xspi->read_fn = xspi_read32;
xspi->write_fn = xspi_write32; xspi->write_fn = xspi_write32;
} else { } else {
xspi->read_fn = xspi_read32_be; xspi->read_fn = xspi_read32_be;
xspi->write_fn = xspi_write32_be; xspi->write_fn = xspi_write32_be;
} }
xspi->bits_per_word = pdata->bits_per_word; xspi->bits_per_word = bits_per_word;
if (xspi->bits_per_word == 8) { if (xspi->bits_per_word == 8) {
xspi->tx_fn = xspi_tx8; xspi->tx_fn = xspi_tx8;
xspi->rx_fn = xspi_rx8; xspi->rx_fn = xspi_rx8;
...@@ -462,6 +466,97 @@ void xilinx_spi_deinit(struct spi_master *master) ...@@ -462,6 +466,97 @@ void xilinx_spi_deinit(struct spi_master *master)
} }
EXPORT_SYMBOL(xilinx_spi_deinit); EXPORT_SYMBOL(xilinx_spi_deinit);
static int __devinit xilinx_spi_probe(struct platform_device *dev)
{
struct xspi_platform_data *pdata;
struct resource *r;
int irq, num_cs = 0, little_endian = 0, bits_per_word = 8;
struct spi_master *master;
u8 i;
pdata = dev->dev.platform_data;
if (pdata) {
num_cs = pdata->num_chipselect;
little_endian = pdata->little_endian;
bits_per_word = pdata->bits_per_word;
}
#ifdef CONFIG_OF
if (dev->dev.of_node) {
const __be32 *prop;
int len;
/* number of slave select bits is required */
prop = of_get_property(dev->dev.of_node, "xlnx,num-ss-bits",
&len);
if (prop && len >= sizeof(*prop))
num_cs = __be32_to_cpup(prop);
}
#endif
if (!num_cs) {
dev_err(&dev->dev, "Missing slave select configuration data\n");
return -EINVAL;
}
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
irq = platform_get_irq(dev, 0);
if (irq < 0)
return -ENXIO;
master = xilinx_spi_init(&dev->dev, r, irq, dev->id, num_cs,
little_endian, bits_per_word);
if (!master)
return -ENODEV;
if (pdata) {
for (i = 0; i < pdata->num_devices; i++)
spi_new_device(master, pdata->devices + i);
}
platform_set_drvdata(dev, master);
return 0;
}
static int __devexit xilinx_spi_remove(struct platform_device *dev)
{
xilinx_spi_deinit(platform_get_drvdata(dev));
platform_set_drvdata(dev, 0);
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" XILINX_SPI_NAME);
static struct platform_driver xilinx_spi_driver = {
.probe = xilinx_spi_probe,
.remove = __devexit_p(xilinx_spi_remove),
.driver = {
.name = XILINX_SPI_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = xilinx_spi_of_match,
#endif
},
};
static int __init xilinx_spi_pltfm_init(void)
{
return platform_driver_register(&xilinx_spi_driver);
}
module_init(xilinx_spi_pltfm_init);
static void __exit xilinx_spi_pltfm_exit(void)
{
platform_driver_unregister(&xilinx_spi_driver);
}
module_exit(xilinx_spi_pltfm_exit);
MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>"); MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
MODULE_DESCRIPTION("Xilinx SPI driver"); MODULE_DESCRIPTION("Xilinx SPI driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/*
* Xilinx SPI device driver API and platform data header file
*
* Copyright (c) 2009 Intel Corporation
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _XILINX_SPI_H_
#define _XILINX_SPI_H_
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#define XILINX_SPI_NAME "xilinx_spi"
struct spi_master *xilinx_spi_init(struct device *dev, struct resource *mem,
u32 irq, s16 bus_num);
void xilinx_spi_deinit(struct spi_master *master);
#endif
/*
* Xilinx SPI OF device driver
*
* Copyright (c) 2009 Intel Corporation
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports:
* Xilinx SPI devices as OF devices
*
* Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/of_spi.h>
#include <linux/spi/xilinx_spi.h>
#include "xilinx_spi.h"
static int __devinit xilinx_spi_of_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct spi_master *master;
struct xspi_platform_data *pdata;
struct resource r_mem;
struct resource r_irq;
int rc = 0;
const u32 *prop;
int len;
rc = of_address_to_resource(ofdev->dev.of_node, 0, &r_mem);
if (rc) {
dev_warn(&ofdev->dev, "invalid address\n");
return rc;
}
rc = of_irq_to_resource(ofdev->dev.of_node, 0, &r_irq);
if (rc == NO_IRQ) {
dev_warn(&ofdev->dev, "no IRQ found\n");
return -ENODEV;
}
ofdev->dev.platform_data =
kzalloc(sizeof(struct xspi_platform_data), GFP_KERNEL);
pdata = ofdev->dev.platform_data;
if (!pdata)
return -ENOMEM;
/* number of slave select bits is required */
prop = of_get_property(ofdev->dev.of_node, "xlnx,num-ss-bits", &len);
if (!prop || len < sizeof(*prop)) {
dev_warn(&ofdev->dev, "no 'xlnx,num-ss-bits' property\n");
return -EINVAL;
}
pdata->num_chipselect = *prop;
pdata->bits_per_word = 8;
master = xilinx_spi_init(&ofdev->dev, &r_mem, r_irq.start, -1);
if (!master)
return -ENODEV;
dev_set_drvdata(&ofdev->dev, master);
return 0;
}
static int __devexit xilinx_spi_remove(struct platform_device *ofdev)
{
xilinx_spi_deinit(dev_get_drvdata(&ofdev->dev));
dev_set_drvdata(&ofdev->dev, 0);
kfree(ofdev->dev.platform_data);
ofdev->dev.platform_data = NULL;
return 0;
}
static int __exit xilinx_spi_of_remove(struct platform_device *op)
{
return xilinx_spi_remove(op);
}
static const struct of_device_id xilinx_spi_of_match[] = {
{ .compatible = "xlnx,xps-spi-2.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.b", },
{}
};
MODULE_DEVICE_TABLE(of, xilinx_spi_of_match);
static struct of_platform_driver xilinx_spi_of_driver = {
.probe = xilinx_spi_of_probe,
.remove = __exit_p(xilinx_spi_of_remove),
.driver = {
.name = "xilinx-xps-spi",
.owner = THIS_MODULE,
.of_match_table = xilinx_spi_of_match,
},
};
static int __init xilinx_spi_of_init(void)
{
return of_register_platform_driver(&xilinx_spi_of_driver);
}
module_init(xilinx_spi_of_init);
static void __exit xilinx_spi_of_exit(void)
{
of_unregister_platform_driver(&xilinx_spi_of_driver);
}
module_exit(xilinx_spi_of_exit);
MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
MODULE_DESCRIPTION("Xilinx SPI platform driver");
MODULE_LICENSE("GPL v2");
/*
* Support for Xilinx SPI platform devices
* Copyright (c) 2009 Intel Corporation
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* Supports:
* Xilinx SPI devices as platform devices
*
* Inspired by xilinx_spi.c, 2002-2007 (c) MontaVista Software, Inc.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/spi/xilinx_spi.h>
#include "xilinx_spi.h"
static int __devinit xilinx_spi_probe(struct platform_device *dev)
{
struct xspi_platform_data *pdata;
struct resource *r;
int irq;
struct spi_master *master;
u8 i;
pdata = dev->dev.platform_data;
if (!pdata)
return -ENODEV;
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
irq = platform_get_irq(dev, 0);
if (irq < 0)
return -ENXIO;
master = xilinx_spi_init(&dev->dev, r, irq, dev->id);
if (!master)
return -ENODEV;
for (i = 0; i < pdata->num_devices; i++)
spi_new_device(master, pdata->devices + i);
platform_set_drvdata(dev, master);
return 0;
}
static int __devexit xilinx_spi_remove(struct platform_device *dev)
{
xilinx_spi_deinit(platform_get_drvdata(dev));
platform_set_drvdata(dev, 0);
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" XILINX_SPI_NAME);
static struct platform_driver xilinx_spi_driver = {
.probe = xilinx_spi_probe,
.remove = __devexit_p(xilinx_spi_remove),
.driver = {
.name = XILINX_SPI_NAME,
.owner = THIS_MODULE,
},
};
static int __init xilinx_spi_pltfm_init(void)
{
return platform_driver_register(&xilinx_spi_driver);
}
module_init(xilinx_spi_pltfm_init);
static void __exit xilinx_spi_pltfm_exit(void)
{
platform_driver_unregister(&xilinx_spi_driver);
}
module_exit(xilinx_spi_pltfm_exit);
MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
MODULE_DESCRIPTION("Xilinx SPI platform driver");
MODULE_LICENSE("GPL v2");
/* /*
* ssp.h * pxa2xx_ssp.h
* *
* Copyright (C) 2003 Russell King, All Rights Reserved. * Copyright (C) 2003 Russell King, All Rights Reserved.
* *
...@@ -16,8 +16,8 @@ ...@@ -16,8 +16,8 @@
* PXA3xx SSP1, SSP2, SSP3, SSP4 * PXA3xx SSP1, SSP2, SSP3, SSP4
*/ */
#ifndef __ASM_ARCH_SSP_H #ifndef __LINUX_SSP_H
#define __ASM_ARCH_SSP_H #define __LINUX_SSP_H
#include <linux/list.h> #include <linux/list.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -71,11 +71,8 @@ ...@@ -71,11 +71,8 @@
#define SSCR1_SPO (1 << 3) /* Motorola SPI SSPSCLK polarity setting */ #define SSCR1_SPO (1 << 3) /* Motorola SPI SSPSCLK polarity setting */
#define SSCR1_SPH (1 << 4) /* Motorola SPI SSPSCLK phase setting */ #define SSCR1_SPH (1 << 4) /* Motorola SPI SSPSCLK phase setting */
#define SSCR1_MWDS (1 << 5) /* Microwire Transmit Data Size */ #define SSCR1_MWDS (1 << 5) /* Microwire Transmit Data Size */
#define SSCR1_TFT (0x000003c0) /* Transmit FIFO Threshold (mask) */
#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
#define SSCR1_RFT (0x00003c00) /* Receive FIFO Threshold (mask) */
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
#define SSSR_ALT_FRM_MASK 3 /* Masks the SFRM signal number */
#define SSSR_TNF (1 << 2) /* Transmit FIFO Not Full */ #define SSSR_TNF (1 << 2) /* Transmit FIFO Not Full */
#define SSSR_RNE (1 << 3) /* Receive FIFO Not Empty */ #define SSSR_RNE (1 << 3) /* Receive FIFO Not Empty */
#define SSSR_BSY (1 << 4) /* SSP Busy */ #define SSSR_BSY (1 << 4) /* SSP Busy */
...@@ -83,6 +80,31 @@ ...@@ -83,6 +80,31 @@
#define SSSR_RFS (1 << 6) /* Receive FIFO Service Request */ #define SSSR_RFS (1 << 6) /* Receive FIFO Service Request */
#define SSSR_ROR (1 << 7) /* Receive FIFO Overrun */ #define SSSR_ROR (1 << 7) /* Receive FIFO Overrun */
#ifdef CONFIG_ARCH_PXA
#define RX_THRESH_DFLT 8
#define TX_THRESH_DFLT 8
#define SSSR_TFL_MASK (0xf << 8) /* Transmit FIFO Level mask */
#define SSSR_RFL_MASK (0xf << 12) /* Receive FIFO Level mask */
#define SSCR1_TFT (0x000003c0) /* Transmit FIFO Threshold (mask) */
#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..16] */
#define SSCR1_RFT (0x00003c00) /* Receive FIFO Threshold (mask) */
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..16] */
#else
#define RX_THRESH_DFLT 2
#define TX_THRESH_DFLT 2
#define SSSR_TFL_MASK (0x3 << 8) /* Transmit FIFO Level mask */
#define SSSR_RFL_MASK (0x3 << 12) /* Receive FIFO Level mask */
#define SSCR1_TFT (0x000000c0) /* Transmit FIFO Threshold (mask) */
#define SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..4] */
#define SSCR1_RFT (0x00000c00) /* Receive FIFO Threshold (mask) */
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
#endif
/* extra bits in PXA255, PXA26x and PXA27x SSP ports */ /* extra bits in PXA255, PXA26x and PXA27x SSP ports */
#define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */ #define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */
...@@ -139,6 +161,7 @@ enum pxa_ssp_type { ...@@ -139,6 +161,7 @@ enum pxa_ssp_type {
PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */ PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
PXA27x_SSP, PXA27x_SSP,
PXA168_SSP, PXA168_SSP,
CE4100_SSP,
}; };
struct ssp_device { struct ssp_device {
...@@ -183,4 +206,4 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg) ...@@ -183,4 +206,4 @@ static inline u32 pxa_ssp_read_reg(struct ssp_device *dev, u32 reg)
struct ssp_device *pxa_ssp_request(int port, const char *label); struct ssp_device *pxa_ssp_request(int port, const char *label);
void pxa_ssp_free(struct ssp_device *); void pxa_ssp_free(struct ssp_device *);
#endif /* __ASM_ARCH_SSP_H */ #endif
#ifndef DW_SPI_HEADER_H #ifndef DW_SPI_HEADER_H
#define DW_SPI_HEADER_H #define DW_SPI_HEADER_H
#include <linux/io.h> #include <linux/io.h>
/* Bit fields in CTRLR0 */ /* Bit fields in CTRLR0 */
...@@ -82,6 +83,13 @@ struct dw_spi_reg { ...@@ -82,6 +83,13 @@ struct dw_spi_reg {
though only low 16 bits matters */ though only low 16 bits matters */
} __packed; } __packed;
struct dw_spi;
struct dw_spi_dma_ops {
int (*dma_init)(struct dw_spi *dws);
void (*dma_exit)(struct dw_spi *dws);
int (*dma_transfer)(struct dw_spi *dws, int cs_change);
};
struct dw_spi { struct dw_spi {
struct spi_master *master; struct spi_master *master;
struct spi_device *cur_dev; struct spi_device *cur_dev;
...@@ -136,13 +144,15 @@ struct dw_spi { ...@@ -136,13 +144,15 @@ struct dw_spi {
/* Dma info */ /* Dma info */
int dma_inited; int dma_inited;
struct dma_chan *txchan; struct dma_chan *txchan;
struct scatterlist tx_sgl;
struct dma_chan *rxchan; struct dma_chan *rxchan;
int txdma_done; struct scatterlist rx_sgl;
int rxdma_done; int dma_chan_done;
u64 tx_param;
u64 rx_param;
struct device *dma_dev; struct device *dma_dev;
dma_addr_t dma_addr; dma_addr_t dma_addr; /* phy address of the Data register */
struct dw_spi_dma_ops *dma_ops;
void *dma_priv; /* platform relate info */
struct pci_dev *dmac;
/* Bus interface info */ /* Bus interface info */
void *priv; void *priv;
...@@ -216,4 +226,8 @@ extern int dw_spi_add_host(struct dw_spi *dws); ...@@ -216,4 +226,8 @@ extern int dw_spi_add_host(struct dw_spi *dws);
extern void dw_spi_remove_host(struct dw_spi *dws); extern void dw_spi_remove_host(struct dw_spi *dws);
extern int dw_spi_suspend_host(struct dw_spi *dws); extern int dw_spi_suspend_host(struct dw_spi *dws);
extern int dw_spi_resume_host(struct dw_spi *dws); extern int dw_spi_resume_host(struct dw_spi *dws);
extern void dw_spi_xfer_done(struct dw_spi *dws);
/* platform related setup */
extern int dw_spi_mid_init(struct dw_spi *dws); /* Intel MID platforms */
#endif /* DW_SPI_HEADER_H */ #endif /* DW_SPI_HEADER_H */
/*
* Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __linux_pxa2xx_spi_h
#define __linux_pxa2xx_spi_h
#include <linux/pxa2xx_ssp.h>
#define PXA2XX_CS_ASSERT (0x01)
#define PXA2XX_CS_DEASSERT (0x02)
/* device.platform_data for SSP controller devices */
struct pxa2xx_spi_master {
u32 clock_enable;
u16 num_chipselect;
u8 enable_dma;
};
/* spi_board_info.controller_data for SPI slave devices,
* copied to spi_device.platform_data ... mostly for dma tuning
*/
struct pxa2xx_spi_chip {
u8 tx_threshold;
u8 rx_threshold;
u8 dma_burst_size;
u32 timeout;
u8 enable_loopback;
int gpio_cs;
void (*cs_control)(u32 command);
};
#ifdef CONFIG_ARCH_PXA
#include <linux/clk.h>
#include <mach/dma.h>
extern void pxa2xx_set_spi_info(unsigned id, struct pxa2xx_spi_master *info);
#else
/*
* This is the implemtation for CE4100 on x86. ARM defines them in mach/ or
* plat/ include path.
* The CE4100 does not provide DMA support. This bits are here to let the driver
* compile and will never be used. Maybe we get DMA support at a later point in
* time.
*/
#define DCSR(n) (n)
#define DSADR(n) (n)
#define DTADR(n) (n)
#define DCMD(n) (n)
#define DRCMR(n) (n)
#define DCSR_RUN (1 << 31) /* Run Bit */
#define DCSR_NODESC (1 << 30) /* No-Descriptor Fetch */
#define DCSR_STOPIRQEN (1 << 29) /* Stop Interrupt Enable */
#define DCSR_REQPEND (1 << 8) /* Request Pending (read-only) */
#define DCSR_STOPSTATE (1 << 3) /* Stop State (read-only) */
#define DCSR_ENDINTR (1 << 2) /* End Interrupt */
#define DCSR_STARTINTR (1 << 1) /* Start Interrupt */
#define DCSR_BUSERR (1 << 0) /* Bus Error Interrupt */
#define DCSR_EORIRQEN (1 << 28) /* End of Receive Interrupt Enable */
#define DCSR_EORJMPEN (1 << 27) /* Jump to next descriptor on EOR */
#define DCSR_EORSTOPEN (1 << 26) /* STOP on an EOR */
#define DCSR_SETCMPST (1 << 25) /* Set Descriptor Compare Status */
#define DCSR_CLRCMPST (1 << 24) /* Clear Descriptor Compare Status */
#define DCSR_CMPST (1 << 10) /* The Descriptor Compare Status */
#define DCSR_EORINTR (1 << 9) /* The end of Receive */
#define DRCMR_MAPVLD (1 << 7) /* Map Valid */
#define DRCMR_CHLNUM 0x1f /* mask for Channel Number */
#define DDADR_DESCADDR 0xfffffff0 /* Address of next descriptor */
#define DDADR_STOP (1 << 0) /* Stop */
#define DCMD_INCSRCADDR (1 << 31) /* Source Address Increment Setting. */
#define DCMD_INCTRGADDR (1 << 30) /* Target Address Increment Setting. */
#define DCMD_FLOWSRC (1 << 29) /* Flow Control by the source. */
#define DCMD_FLOWTRG (1 << 28) /* Flow Control by the target. */
#define DCMD_STARTIRQEN (1 << 22) /* Start Interrupt Enable */
#define DCMD_ENDIRQEN (1 << 21) /* End Interrupt Enable */
#define DCMD_ENDIAN (1 << 18) /* Device Endian-ness. */
#define DCMD_BURST8 (1 << 16) /* 8 byte burst */
#define DCMD_BURST16 (2 << 16) /* 16 byte burst */
#define DCMD_BURST32 (3 << 16) /* 32 byte burst */
#define DCMD_WIDTH1 (1 << 14) /* 1 byte width */
#define DCMD_WIDTH2 (2 << 14) /* 2 byte width (HalfWord) */
#define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */
#define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */
/*
* Descriptor structure for PXA's DMA engine
* Note: this structure must always be aligned to a 16-byte boundary.
*/
typedef enum {
DMA_PRIO_HIGH = 0,
DMA_PRIO_MEDIUM = 1,
DMA_PRIO_LOW = 2
} pxa_dma_prio;
/*
* DMA registration
*/
static inline int pxa_request_dma(char *name,
pxa_dma_prio prio,
void (*irq_handler)(int, void *),
void *data)
{
return -ENODEV;
}
static inline void pxa_free_dma(int dma_ch)
{
}
/*
* The CE4100 does not have the clk framework implemented and SPI clock can
* not be switched on/off or the divider changed.
*/
static inline void clk_disable(struct clk *clk)
{
}
static inline int clk_enable(struct clk *clk)
{
return 0;
}
static inline unsigned long clk_get_rate(struct clk *clk)
{
return 3686400;
}
#endif
#endif
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/pxa2xx_ssp.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -33,7 +34,6 @@ ...@@ -33,7 +34,6 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/dma.h> #include <mach/dma.h>
#include <mach/audio.h> #include <mach/audio.h>
#include <plat/ssp.h>
#include "../../arm/pxa2xx-pcm.h" #include "../../arm/pxa2xx-pcm.h"
#include "pxa-ssp.h" #include "pxa-ssp.h"
......
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