dect
/
linux-2.6
Archived
13
0
Fork 0

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
  ...
This commit is contained in:
Linus Torvalds 2011-01-07 17:08:46 -08:00
commit 021db8e2bd
45 changed files with 1607 additions and 1376 deletions

View File

@ -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
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.

View File

@ -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",

View File

@ -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[] = {

View File

@ -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 */

View File

@ -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"

View File

@ -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"

View File

@ -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 @@
#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>

View File

@ -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 @@
#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>

View File

@ -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 @@
#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"

View File

@ -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 @@
#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>

View File

@ -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"

View File

@ -1,47 +0,0 @@
/*
* 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_*/

View File

@ -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 @@
#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>

View File

@ -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>

View File

@ -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"

View File

@ -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 @@
#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>

View File

@ -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 @@
#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>

View File

@ -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>

View File

@ -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 @@
#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>

View File

@ -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>

View File

@ -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 @@
#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>

View File

@ -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 @@
#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>

View File

@ -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);

View File

@ -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
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
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
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
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

View File

@ -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
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

View File

@ -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 {
* @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 {
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)
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)
}; };
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)
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)
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)
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 @@ err_txdesc:
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)
/* 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)
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)
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)
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)
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)
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)
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);

File diff suppressed because it is too large Load Diff

View File

@ -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)
*/ */
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)
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)
} 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)
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)
*/ */
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)
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)
} }
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)
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)
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 @@ err_free_master:
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)
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)
/* 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)
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)
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");

223
drivers/spi/dw_spi_mid.c Normal file
View File

@ -0,0 +1,223 @@
/*
* 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;
}

View File

@ -1,5 +1,5 @@
/* /*
* 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.
* *
@ -26,8 +26,8 @@
#define DRIVER_NAME "dw_spi_pci" #define DRIVER_NAME "dw_spi_pci"
struct dw_spi_pci { struct dw_spi_pci {
struct pci_dev *pdev; struct pci_dev *pdev;
struct dw_spi dws; struct dw_spi dws;
}; };
static int __devinit spi_pci_probe(struct pci_dev *pdev, 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)
#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) },
{}, {},
}; };

View File

@ -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 @@ free_master:
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,
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);
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,

View File

@ -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)
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)
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)
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;
} }

View File

@ -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 @@
#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");
#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 {
u8 enable_dma; u8 enable_dma;
u8 bits_per_word; u8 bits_per_word;
u32 speed_hz; u32 speed_hz;
int gpio_cs; union {
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)
{ {
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)
{ {
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)
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)
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)
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)
{ {
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)
{ {
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)
{ {
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)
/* 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)
/* 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)
/* 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)
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)
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)
} }
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 (pxa25x_ssp_comp(drv_data)) {
sccr1_reg &= ~SSCR1_RFT;
bytes_left = drv_data->rx_end - drv_data->rx;
switch (drv_data->n_bytes) {
case 4:
bytes_left >>= 1;
case 2:
bytes_left >>= 1;
} }
if (!drv_data->read(drv_data))
{ if (bytes_left > RX_THRESH_DFLT)
int_error_stop(drv_data, bytes_left = RX_THRESH_DFLT;
"interrupt_transfer: "
"trailing byte read failed"); sccr1_reg |= SSCR1_RxTresh(bytes_left);
return IRQ_HANDLED;
}
int_transfer_complete(drv_data);
} }
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)
{ {
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)
{ {
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)
/* 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)
/* 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)
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)
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,7 +1317,17 @@ static int setup(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
} }
chip->gpio_cs = -1; 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->enable_dma = 0; chip->enable_dma = 0;
chip->timeout = TIMOUT_DFLT; chip->timeout = TIMOUT_DFLT;
chip->dma_burst_size = drv_data->master_info->enable_dma ? chip->dma_burst_size = drv_data->master_info->enable_dma ?
@ -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)
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)
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)
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)
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)
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)
| 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 = {
.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);

View File

@ -0,0 +1,201 @@
/*
* 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>");

View File

@ -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)
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,30 +798,8 @@ 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) { spi_imx->devtype_data =
if (cpu_is_mx25() || cpu_is_mx35()) spi_imx_devtype_data[pdev->id_entry->driver_data];
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[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) {
@ -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;
} }

View File

@ -449,7 +449,7 @@ err_iomap:
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;

View File

@ -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)
{ {
/* 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);

View File

@ -1,26 +1,27 @@
/* /*
* 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)
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,
} }
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)
} }
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");

View File

@ -1,32 +0,0 @@
/*
* 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

View File

@ -1,133 +0,0 @@
/*
* 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");

View File

@ -1,102 +0,0 @@
/*
* 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");

View File

@ -1,5 +1,5 @@
/* /*
* 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 @@
* 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 @@
#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 @@
#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 {
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)
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

View File

@ -1,5 +1,6 @@
#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 {
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 {
/* 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);
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 */

View File

@ -0,0 +1,152 @@
/*
* 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

View File

@ -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 @@
#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"