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

* 'spi/next' of git://git.secretlab.ca/git/linux-2.6: (34 commits)
  spi/imx: add device tree probe support
  spi/imx: copy gpio number passed by platform data into driver private data
  spi/imx: use soc name in spi device type naming scheme
  spi/imx: merge type SPI_IMX_VER_0_7 into SPI_IMX_VER_0_4
  spi/imx: do not use spi_imx2_3 to name SPI_IMX_VER_2_3 function and macro
  spi/imx: use mx21 to name SPI_IMX_VER_0_0 function and macro
  spi/imx: do not make copy of spi_imx_devtype_data
  spi/dw: Add spi number into spi irq desc
  spi/tegra: Use engineering names in DT compatible property
  spi/fsl_spi: fix CPM spi driver
  mach-s3c2410: remove unused spi-gpio.h file
  spi: remove obsolete spi-s3c24xx-gpio driver
  mach-gta2: remove unused spi-gpio.h include
  mach-qt2410: convert to spi_gpio
  mach-jive: convert to spi_gpio
  spi/pxa2xx: Remove unavailable ssp_type from documentation
  spi/bfin_spi: uninline fat queue funcs
  spi/bfin_spi: constify pin array
  spi/bfin_spi: use structs for accessing hardware regs
  spi/topcliff-pch: Support new device ML7223 IOH
  ...

Fix up trivial conflict in arch/arm/mach-ep93xx/Makefile
This commit is contained in:
Linus Torvalds 2011-07-22 14:52:44 -07:00
commit 7235dd74a4
80 changed files with 3492 additions and 1995 deletions

View File

@ -0,0 +1,22 @@
* Freescale (Enhanced) Configurable Serial Peripheral Interface
(CSPI/eCSPI) for i.MX
Required properties:
- compatible : Should be "fsl,<soc>-cspi" or "fsl,<soc>-ecspi"
- reg : Offset and length of the register set for the device
- interrupts : Should contain CSPI/eCSPI interrupt
- fsl,spi-num-chipselects : Contains the number of the chipselect
- cs-gpios : Specifies the gpio pins to be used for chipselects.
Example:
ecspi@70010000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "fsl,imx51-ecspi";
reg = <0x70010000 0x4000>;
interrupts = <36>;
fsl,spi-num-chipselects = <2>;
cs-gpios = <&gpio3 24 0>, /* GPIO4_24 */
<&gpio3 25 0>; /* GPIO4_25 */
};

View File

@ -0,0 +1,5 @@
NVIDIA Tegra 2 SPI device
Required properties:
- compatible : should be "nvidia,tegra20-spi".
- gpios : should specify GPIOs used for chipselect.

View File

@ -88,6 +88,16 @@ static void __init ts72xx_init_machine(void)
ARRAY_SIZE(ts72xx_spi_devices));
}
The driver can use DMA for the transfers also. In this case ts72xx_spi_info
becomes:
static struct ep93xx_spi_info ts72xx_spi_info = {
.num_chipselect = ARRAY_SIZE(ts72xx_spi_devices),
.use_dma = true;
};
Note that CONFIG_EP93XX_DMA should be enabled as well.
Thanks to
=========
Martin Guy, H. Hartley Sweeten and others who helped me during development of

View File

@ -22,15 +22,11 @@ Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
found in include/linux/spi/pxa2xx_spi.h:
struct pxa2xx_spi_master {
enum pxa_ssp_type ssp_type;
u32 clock_enable;
u16 num_chipselect;
u8 enable_dma;
};
The "pxa2xx_spi_master.ssp_type" field must have a value between 1 and 3 and
informs the driver which features a particular SSP supports.
The "pxa2xx_spi_master.clock_enable" field is used to enable/disable the
corresponding SSP peripheral block in the "Clock Enable Register (CKEN"). See
the "PXA2xx Developer Manual" section "Clocks and Power Management".
@ -61,7 +57,6 @@ static struct resource pxa_spi_nssp_resources[] = {
};
static struct pxa2xx_spi_master pxa_nssp_master_info = {
.ssp_type = PXA25x_NSSP, /* Type of SSP */
.clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */
.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
.enable_dma = 1, /* Enables NSSP DMA */

View File

@ -1,11 +1,13 @@
#
# Makefile for the linux kernel.
#
obj-y := core.o clock.o dma-m2p.o
obj-y := core.o clock.o
obj-m :=
obj-n :=
obj- :=
obj-$(CONFIG_EP93XX_DMA) += dma.o
obj-$(CONFIG_MACH_ADSSPHERE) += adssphere.o
obj-$(CONFIG_MACH_EDB93XX) += edb93xx.o
obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o

View File

@ -506,11 +506,15 @@ static struct resource ep93xx_spi_resources[] = {
},
};
static u64 ep93xx_spi_dma_mask = DMA_BIT_MASK(32);
static struct platform_device ep93xx_spi_device = {
.name = "ep93xx-spi",
.id = 0,
.dev = {
.platform_data = &ep93xx_spi_master_data,
.platform_data = &ep93xx_spi_master_data,
.coherent_dma_mask = DMA_BIT_MASK(32),
.dma_mask = &ep93xx_spi_dma_mask,
},
.num_resources = ARRAY_SIZE(ep93xx_spi_resources),
.resource = ep93xx_spi_resources,

View File

@ -1,411 +0,0 @@
/*
* arch/arm/mach-ep93xx/dma-m2p.c
* M2P DMA handling for Cirrus EP93xx chips.
*
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
* Copyright (C) 2006 Applied Data Systems
*
* Copyright (C) 2009 Ryan Mallon <ryan@bluewatersys.com>
*
* 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.
*/
/*
* On the EP93xx chip the following peripherals my be allocated to the 10
* Memory to Internal Peripheral (M2P) channels (5 transmit + 5 receive).
*
* I2S contains 3 Tx and 3 Rx DMA Channels
* AAC contains 3 Tx and 3 Rx DMA Channels
* UART1 contains 1 Tx and 1 Rx DMA Channels
* UART2 contains 1 Tx and 1 Rx DMA Channels
* UART3 contains 1 Tx and 1 Rx DMA Channels
* IrDA contains 1 Tx and 1 Rx DMA Channels
*
* SSP and IDE use the Memory to Memory (M2M) channels and are not covered
* with this implementation.
*/
#define pr_fmt(fmt) "ep93xx " KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/io.h>
#include <mach/dma.h>
#include <mach/hardware.h>
#define M2P_CONTROL 0x00
#define M2P_CONTROL_STALL_IRQ_EN (1 << 0)
#define M2P_CONTROL_NFB_IRQ_EN (1 << 1)
#define M2P_CONTROL_ERROR_IRQ_EN (1 << 3)
#define M2P_CONTROL_ENABLE (1 << 4)
#define M2P_INTERRUPT 0x04
#define M2P_INTERRUPT_STALL (1 << 0)
#define M2P_INTERRUPT_NFB (1 << 1)
#define M2P_INTERRUPT_ERROR (1 << 3)
#define M2P_PPALLOC 0x08
#define M2P_STATUS 0x0c
#define M2P_REMAIN 0x14
#define M2P_MAXCNT0 0x20
#define M2P_BASE0 0x24
#define M2P_MAXCNT1 0x30
#define M2P_BASE1 0x34
#define STATE_IDLE 0 /* Channel is inactive. */
#define STATE_STALL 1 /* Channel is active, no buffers pending. */
#define STATE_ON 2 /* Channel is active, one buffer pending. */
#define STATE_NEXT 3 /* Channel is active, two buffers pending. */
struct m2p_channel {
char *name;
void __iomem *base;
int irq;
struct clk *clk;
spinlock_t lock;
void *client;
unsigned next_slot:1;
struct ep93xx_dma_buffer *buffer_xfer;
struct ep93xx_dma_buffer *buffer_next;
struct list_head buffers_pending;
};
static struct m2p_channel m2p_rx[] = {
{"m2p1", EP93XX_DMA_BASE + 0x0040, IRQ_EP93XX_DMAM2P1},
{"m2p3", EP93XX_DMA_BASE + 0x00c0, IRQ_EP93XX_DMAM2P3},
{"m2p5", EP93XX_DMA_BASE + 0x0200, IRQ_EP93XX_DMAM2P5},
{"m2p7", EP93XX_DMA_BASE + 0x0280, IRQ_EP93XX_DMAM2P7},
{"m2p9", EP93XX_DMA_BASE + 0x0300, IRQ_EP93XX_DMAM2P9},
{NULL},
};
static struct m2p_channel m2p_tx[] = {
{"m2p0", EP93XX_DMA_BASE + 0x0000, IRQ_EP93XX_DMAM2P0},
{"m2p2", EP93XX_DMA_BASE + 0x0080, IRQ_EP93XX_DMAM2P2},
{"m2p4", EP93XX_DMA_BASE + 0x0240, IRQ_EP93XX_DMAM2P4},
{"m2p6", EP93XX_DMA_BASE + 0x02c0, IRQ_EP93XX_DMAM2P6},
{"m2p8", EP93XX_DMA_BASE + 0x0340, IRQ_EP93XX_DMAM2P8},
{NULL},
};
static void feed_buf(struct m2p_channel *ch, struct ep93xx_dma_buffer *buf)
{
if (ch->next_slot == 0) {
writel(buf->size, ch->base + M2P_MAXCNT0);
writel(buf->bus_addr, ch->base + M2P_BASE0);
} else {
writel(buf->size, ch->base + M2P_MAXCNT1);
writel(buf->bus_addr, ch->base + M2P_BASE1);
}
ch->next_slot ^= 1;
}
static void choose_buffer_xfer(struct m2p_channel *ch)
{
struct ep93xx_dma_buffer *buf;
ch->buffer_xfer = NULL;
if (!list_empty(&ch->buffers_pending)) {
buf = list_entry(ch->buffers_pending.next,
struct ep93xx_dma_buffer, list);
list_del(&buf->list);
feed_buf(ch, buf);
ch->buffer_xfer = buf;
}
}
static void choose_buffer_next(struct m2p_channel *ch)
{
struct ep93xx_dma_buffer *buf;
ch->buffer_next = NULL;
if (!list_empty(&ch->buffers_pending)) {
buf = list_entry(ch->buffers_pending.next,
struct ep93xx_dma_buffer, list);
list_del(&buf->list);
feed_buf(ch, buf);
ch->buffer_next = buf;
}
}
static inline void m2p_set_control(struct m2p_channel *ch, u32 v)
{
/*
* The control register must be read immediately after being written so
* that the internal state machine is correctly updated. See the ep93xx
* users' guide for details.
*/
writel(v, ch->base + M2P_CONTROL);
readl(ch->base + M2P_CONTROL);
}
static inline int m2p_channel_state(struct m2p_channel *ch)
{
return (readl(ch->base + M2P_STATUS) >> 4) & 0x3;
}
static irqreturn_t m2p_irq(int irq, void *dev_id)
{
struct m2p_channel *ch = dev_id;
struct ep93xx_dma_m2p_client *cl;
u32 irq_status, v;
int error = 0;
cl = ch->client;
spin_lock(&ch->lock);
irq_status = readl(ch->base + M2P_INTERRUPT);
if (irq_status & M2P_INTERRUPT_ERROR) {
writel(M2P_INTERRUPT_ERROR, ch->base + M2P_INTERRUPT);
error = 1;
}
if ((irq_status & (M2P_INTERRUPT_STALL | M2P_INTERRUPT_NFB)) == 0) {
spin_unlock(&ch->lock);
return IRQ_NONE;
}
switch (m2p_channel_state(ch)) {
case STATE_IDLE:
pr_crit("dma interrupt without a dma buffer\n");
BUG();
break;
case STATE_STALL:
cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error);
if (ch->buffer_next != NULL) {
cl->buffer_finished(cl->cookie, ch->buffer_next,
0, error);
}
choose_buffer_xfer(ch);
choose_buffer_next(ch);
if (ch->buffer_xfer != NULL)
cl->buffer_started(cl->cookie, ch->buffer_xfer);
break;
case STATE_ON:
cl->buffer_finished(cl->cookie, ch->buffer_xfer, 0, error);
ch->buffer_xfer = ch->buffer_next;
choose_buffer_next(ch);
cl->buffer_started(cl->cookie, ch->buffer_xfer);
break;
case STATE_NEXT:
pr_crit("dma interrupt while next\n");
BUG();
break;
}
v = readl(ch->base + M2P_CONTROL) & ~(M2P_CONTROL_STALL_IRQ_EN |
M2P_CONTROL_NFB_IRQ_EN);
if (ch->buffer_xfer != NULL)
v |= M2P_CONTROL_STALL_IRQ_EN;
if (ch->buffer_next != NULL)
v |= M2P_CONTROL_NFB_IRQ_EN;
m2p_set_control(ch, v);
spin_unlock(&ch->lock);
return IRQ_HANDLED;
}
static struct m2p_channel *find_free_channel(struct ep93xx_dma_m2p_client *cl)
{
struct m2p_channel *ch;
int i;
if (cl->flags & EP93XX_DMA_M2P_RX)
ch = m2p_rx;
else
ch = m2p_tx;
for (i = 0; ch[i].base; i++) {
struct ep93xx_dma_m2p_client *client;
client = ch[i].client;
if (client != NULL) {
int port;
port = cl->flags & EP93XX_DMA_M2P_PORT_MASK;
if (port == (client->flags &
EP93XX_DMA_M2P_PORT_MASK)) {
pr_warning("DMA channel already used by %s\n",
cl->name ? : "unknown client");
return ERR_PTR(-EBUSY);
}
}
}
for (i = 0; ch[i].base; i++) {
if (ch[i].client == NULL)
return ch + i;
}
pr_warning("No free DMA channel for %s\n",
cl->name ? : "unknown client");
return ERR_PTR(-ENODEV);
}
static void channel_enable(struct m2p_channel *ch)
{
struct ep93xx_dma_m2p_client *cl = ch->client;
u32 v;
clk_enable(ch->clk);
v = cl->flags & EP93XX_DMA_M2P_PORT_MASK;
writel(v, ch->base + M2P_PPALLOC);
v = cl->flags & EP93XX_DMA_M2P_ERROR_MASK;
v |= M2P_CONTROL_ENABLE | M2P_CONTROL_ERROR_IRQ_EN;
m2p_set_control(ch, v);
}
static void channel_disable(struct m2p_channel *ch)
{
u32 v;
v = readl(ch->base + M2P_CONTROL);
v &= ~(M2P_CONTROL_STALL_IRQ_EN | M2P_CONTROL_NFB_IRQ_EN);
m2p_set_control(ch, v);
while (m2p_channel_state(ch) >= STATE_ON)
cpu_relax();
m2p_set_control(ch, 0x0);
while (m2p_channel_state(ch) == STATE_STALL)
cpu_relax();
clk_disable(ch->clk);
}
int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *cl)
{
struct m2p_channel *ch;
int err;
ch = find_free_channel(cl);
if (IS_ERR(ch))
return PTR_ERR(ch);
err = request_irq(ch->irq, m2p_irq, 0, cl->name ? : "dma-m2p", ch);
if (err)
return err;
ch->client = cl;
ch->next_slot = 0;
ch->buffer_xfer = NULL;
ch->buffer_next = NULL;
INIT_LIST_HEAD(&ch->buffers_pending);
cl->channel = ch;
channel_enable(ch);
return 0;
}
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_register);
void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *cl)
{
struct m2p_channel *ch = cl->channel;
channel_disable(ch);
free_irq(ch->irq, ch);
ch->client = NULL;
}
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_client_unregister);
void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *cl,
struct ep93xx_dma_buffer *buf)
{
struct m2p_channel *ch = cl->channel;
unsigned long flags;
u32 v;
spin_lock_irqsave(&ch->lock, flags);
v = readl(ch->base + M2P_CONTROL);
if (ch->buffer_xfer == NULL) {
ch->buffer_xfer = buf;
feed_buf(ch, buf);
cl->buffer_started(cl->cookie, buf);
v |= M2P_CONTROL_STALL_IRQ_EN;
m2p_set_control(ch, v);
} else if (ch->buffer_next == NULL) {
ch->buffer_next = buf;
feed_buf(ch, buf);
v |= M2P_CONTROL_NFB_IRQ_EN;
m2p_set_control(ch, v);
} else {
list_add_tail(&buf->list, &ch->buffers_pending);
}
spin_unlock_irqrestore(&ch->lock, flags);
}
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit);
void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *cl,
struct ep93xx_dma_buffer *buf)
{
struct m2p_channel *ch = cl->channel;
list_add_tail(&buf->list, &ch->buffers_pending);
}
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_submit_recursive);
void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *cl)
{
struct m2p_channel *ch = cl->channel;
channel_disable(ch);
ch->next_slot = 0;
ch->buffer_xfer = NULL;
ch->buffer_next = NULL;
INIT_LIST_HEAD(&ch->buffers_pending);
channel_enable(ch);
}
EXPORT_SYMBOL_GPL(ep93xx_dma_m2p_flush);
static int init_channel(struct m2p_channel *ch)
{
ch->clk = clk_get(NULL, ch->name);
if (IS_ERR(ch->clk))
return PTR_ERR(ch->clk);
spin_lock_init(&ch->lock);
ch->client = NULL;
return 0;
}
static int __init ep93xx_dma_m2p_init(void)
{
int i;
int ret;
for (i = 0; m2p_rx[i].base; i++) {
ret = init_channel(m2p_rx + i);
if (ret)
return ret;
}
for (i = 0; m2p_tx[i].base; i++) {
ret = init_channel(m2p_tx + i);
if (ret)
return ret;
}
pr_info("M2P DMA subsystem initialized\n");
return 0;
}
arch_initcall(ep93xx_dma_m2p_init);

108
arch/arm/mach-ep93xx/dma.c Normal file
View File

@ -0,0 +1,108 @@
/*
* arch/arm/mach-ep93xx/dma.c
*
* Platform support code for the EP93xx dmaengine driver.
*
* Copyright (C) 2011 Mika Westerberg
*
* This work is based on the original dma-m2p implementation with
* following copyrights:
*
* Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
* Copyright (C) 2006 Applied Data Systems
* Copyright (C) 2009 Ryan Mallon <rmallon@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*/
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <mach/dma.h>
#include <mach/hardware.h>
#define DMA_CHANNEL(_name, _base, _irq) \
{ .name = (_name), .base = (_base), .irq = (_irq) }
/*
* DMA M2P channels.
*
* On the EP93xx chip the following peripherals my be allocated to the 10
* Memory to Internal Peripheral (M2P) channels (5 transmit + 5 receive).
*
* I2S contains 3 Tx and 3 Rx DMA Channels
* AAC contains 3 Tx and 3 Rx DMA Channels
* UART1 contains 1 Tx and 1 Rx DMA Channels
* UART2 contains 1 Tx and 1 Rx DMA Channels
* UART3 contains 1 Tx and 1 Rx DMA Channels
* IrDA contains 1 Tx and 1 Rx DMA Channels
*
* Registers are mapped statically in ep93xx_map_io().
*/
static struct ep93xx_dma_chan_data ep93xx_dma_m2p_channels[] = {
DMA_CHANNEL("m2p0", EP93XX_DMA_BASE + 0x0000, IRQ_EP93XX_DMAM2P0),
DMA_CHANNEL("m2p1", EP93XX_DMA_BASE + 0x0040, IRQ_EP93XX_DMAM2P1),
DMA_CHANNEL("m2p2", EP93XX_DMA_BASE + 0x0080, IRQ_EP93XX_DMAM2P2),
DMA_CHANNEL("m2p3", EP93XX_DMA_BASE + 0x00c0, IRQ_EP93XX_DMAM2P3),
DMA_CHANNEL("m2p4", EP93XX_DMA_BASE + 0x0240, IRQ_EP93XX_DMAM2P4),
DMA_CHANNEL("m2p5", EP93XX_DMA_BASE + 0x0200, IRQ_EP93XX_DMAM2P5),
DMA_CHANNEL("m2p6", EP93XX_DMA_BASE + 0x02c0, IRQ_EP93XX_DMAM2P6),
DMA_CHANNEL("m2p7", EP93XX_DMA_BASE + 0x0280, IRQ_EP93XX_DMAM2P7),
DMA_CHANNEL("m2p8", EP93XX_DMA_BASE + 0x0340, IRQ_EP93XX_DMAM2P8),
DMA_CHANNEL("m2p9", EP93XX_DMA_BASE + 0x0300, IRQ_EP93XX_DMAM2P9),
};
static struct ep93xx_dma_platform_data ep93xx_dma_m2p_data = {
.channels = ep93xx_dma_m2p_channels,
.num_channels = ARRAY_SIZE(ep93xx_dma_m2p_channels),
};
static struct platform_device ep93xx_dma_m2p_device = {
.name = "ep93xx-dma-m2p",
.id = -1,
.dev = {
.platform_data = &ep93xx_dma_m2p_data,
},
};
/*
* DMA M2M channels.
*
* There are 2 M2M channels which support memcpy/memset and in addition simple
* hardware requests from/to SSP and IDE. We do not implement an external
* hardware requests.
*
* Registers are mapped statically in ep93xx_map_io().
*/
static struct ep93xx_dma_chan_data ep93xx_dma_m2m_channels[] = {
DMA_CHANNEL("m2m0", EP93XX_DMA_BASE + 0x0100, IRQ_EP93XX_DMAM2M0),
DMA_CHANNEL("m2m1", EP93XX_DMA_BASE + 0x0140, IRQ_EP93XX_DMAM2M1),
};
static struct ep93xx_dma_platform_data ep93xx_dma_m2m_data = {
.channels = ep93xx_dma_m2m_channels,
.num_channels = ARRAY_SIZE(ep93xx_dma_m2m_channels),
};
static struct platform_device ep93xx_dma_m2m_device = {
.name = "ep93xx-dma-m2m",
.id = -1,
.dev = {
.platform_data = &ep93xx_dma_m2m_data,
},
};
static int __init ep93xx_dma_init(void)
{
platform_device_register(&ep93xx_dma_m2p_device);
platform_device_register(&ep93xx_dma_m2m_device);
return 0;
}
arch_initcall(ep93xx_dma_init);

View File

@ -1,149 +1,93 @@
/**
* DOC: EP93xx DMA M2P memory to peripheral and peripheral to memory engine
*
* The EP93xx DMA M2P subsystem handles DMA transfers between memory and
* peripherals. DMA M2P channels are available for audio, UARTs and IrDA.
* See chapter 10 of the EP93xx users guide for full details on the DMA M2P
* engine.
*
* See sound/soc/ep93xx/ep93xx-pcm.c for an example use of the DMA M2P code.
*
*/
#ifndef __ASM_ARCH_DMA_H
#define __ASM_ARCH_DMA_H
#include <linux/list.h>
#include <linux/types.h>
/**
* struct ep93xx_dma_buffer - Information about a buffer to be transferred
* using the DMA M2P engine
*
* @list: Entry in DMA buffer list
* @bus_addr: Physical address of the buffer
* @size: Size of the buffer in bytes
*/
struct ep93xx_dma_buffer {
struct list_head list;
u32 bus_addr;
u16 size;
};
/**
* struct ep93xx_dma_m2p_client - Information about a DMA M2P client
*
* @name: Unique name for this client
* @flags: Client flags
* @cookie: User data to pass to callback functions
* @buffer_started: Non NULL function to call when a transfer is started.
* The arguments are the user data cookie and the DMA
* buffer which is starting.
* @buffer_finished: Non NULL function to call when a transfer is completed.
* The arguments are the user data cookie, the DMA buffer
* which has completed, and a boolean flag indicating if
* the transfer had an error.
*/
struct ep93xx_dma_m2p_client {
char *name;
u8 flags;
void *cookie;
void (*buffer_started)(void *cookie,
struct ep93xx_dma_buffer *buf);
void (*buffer_finished)(void *cookie,
struct ep93xx_dma_buffer *buf,
int bytes, int error);
/* private: Internal use only */
void *channel;
};
/* DMA M2P ports */
#define EP93XX_DMA_M2P_PORT_I2S1 0x00
#define EP93XX_DMA_M2P_PORT_I2S2 0x01
#define EP93XX_DMA_M2P_PORT_AAC1 0x02
#define EP93XX_DMA_M2P_PORT_AAC2 0x03
#define EP93XX_DMA_M2P_PORT_AAC3 0x04
#define EP93XX_DMA_M2P_PORT_I2S3 0x05
#define EP93XX_DMA_M2P_PORT_UART1 0x06
#define EP93XX_DMA_M2P_PORT_UART2 0x07
#define EP93XX_DMA_M2P_PORT_UART3 0x08
#define EP93XX_DMA_M2P_PORT_IRDA 0x09
#define EP93XX_DMA_M2P_PORT_MASK 0x0f
/* DMA M2P client flags */
#define EP93XX_DMA_M2P_TX 0x00 /* Memory to peripheral */
#define EP93XX_DMA_M2P_RX 0x10 /* Peripheral to memory */
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
/*
* DMA M2P client error handling flags. See the EP93xx users guide
* documentation on the DMA M2P CONTROL register for more details
* M2P channels.
*
* Note that these values are also directly used for setting the PPALLOC
* register.
*/
#define EP93XX_DMA_M2P_ABORT_ON_ERROR 0x20 /* Abort on peripheral error */
#define EP93XX_DMA_M2P_IGNORE_ERROR 0x40 /* Ignore peripheral errors */
#define EP93XX_DMA_M2P_ERROR_MASK 0x60 /* Mask of error bits */
#define EP93XX_DMA_I2S1 0
#define EP93XX_DMA_I2S2 1
#define EP93XX_DMA_AAC1 2
#define EP93XX_DMA_AAC2 3
#define EP93XX_DMA_AAC3 4
#define EP93XX_DMA_I2S3 5
#define EP93XX_DMA_UART1 6
#define EP93XX_DMA_UART2 7
#define EP93XX_DMA_UART3 8
#define EP93XX_DMA_IRDA 9
/* M2M channels */
#define EP93XX_DMA_SSP 10
#define EP93XX_DMA_IDE 11
/**
* ep93xx_dma_m2p_client_register - Register a client with the DMA M2P
* subsystem
* struct ep93xx_dma_data - configuration data for the EP93xx dmaengine
* @port: peripheral which is requesting the channel
* @direction: TX/RX channel
* @name: optional name for the channel, this is displayed in /proc/interrupts
*
* @m2p: Client information to register
* returns 0 on success
*
* The DMA M2P subsystem allocates a channel and an interrupt line for the DMA
* client
* This information is passed as private channel parameter in a filter
* function. Note that this is only needed for slave/cyclic channels. For
* memcpy channels %NULL data should be passed.
*/
int ep93xx_dma_m2p_client_register(struct ep93xx_dma_m2p_client *m2p);
struct ep93xx_dma_data {
int port;
enum dma_data_direction direction;
const char *name;
};
/**
* ep93xx_dma_m2p_client_unregister - Unregister a client from the DMA M2P
* subsystem
*
* @m2p: Client to unregister
*
* Any transfers currently in progress will be completed in hardware, but
* ignored in software.
* struct ep93xx_dma_chan_data - platform specific data for a DMA channel
* @name: name of the channel, used for getting the right clock for the channel
* @base: mapped registers
* @irq: interrupt number used by this channel
*/
void ep93xx_dma_m2p_client_unregister(struct ep93xx_dma_m2p_client *m2p);
struct ep93xx_dma_chan_data {
const char *name;
void __iomem *base;
int irq;
};
/**
* ep93xx_dma_m2p_submit - Submit a DMA M2P transfer
*
* @m2p: DMA Client to submit the transfer on
* @buf: DMA Buffer to submit
*
* If the current or next transfer positions are free on the M2P client then
* the transfer is started immediately. If not, the transfer is added to the
* list of pending transfers. This function must not be called from the
* buffer_finished callback for an M2P channel.
* struct ep93xx_dma_platform_data - platform data for the dmaengine driver
* @channels: array of channels which are passed to the driver
* @num_channels: number of channels in the array
*
* This structure is passed to the DMA engine driver via platform data. For
* M2P channels, contract is that even channels are for TX and odd for RX.
* There is no requirement for the M2M channels.
*/
void ep93xx_dma_m2p_submit(struct ep93xx_dma_m2p_client *m2p,
struct ep93xx_dma_buffer *buf);
struct ep93xx_dma_platform_data {
struct ep93xx_dma_chan_data *channels;
size_t num_channels;
};
static inline bool ep93xx_dma_chan_is_m2p(struct dma_chan *chan)
{
return !strcmp(dev_name(chan->device->dev), "ep93xx-dma-m2p");
}
/**
* ep93xx_dma_m2p_submit_recursive - Put a DMA transfer on the pending list
* for an M2P channel
* ep93xx_dma_chan_direction - returns direction the channel can be used
* @chan: channel
*
* @m2p: DMA Client to submit the transfer on
* @buf: DMA Buffer to submit
*
* This function must only be called from the buffer_finished callback for an
* M2P channel. It is commonly used to add the next transfer in a chained list
* of DMA transfers.
* This function can be used in filter functions to find out whether the
* channel supports given DMA direction. Only M2P channels have such
* limitation, for M2M channels the direction is configurable.
*/
void ep93xx_dma_m2p_submit_recursive(struct ep93xx_dma_m2p_client *m2p,
struct ep93xx_dma_buffer *buf);
static inline enum dma_data_direction
ep93xx_dma_chan_direction(struct dma_chan *chan)
{
if (!ep93xx_dma_chan_is_m2p(chan))
return DMA_NONE;
/**
* ep93xx_dma_m2p_flush - Flush all pending transfers on a DMA M2P client
*
* @m2p: DMA client to flush transfers on
*
* Any transfers currently in progress will be completed in hardware, but
* ignored in software.
*
*/
void ep93xx_dma_m2p_flush(struct ep93xx_dma_m2p_client *m2p);
/* even channels are for TX, odd for RX */
return (chan->chan_id % 2 == 0) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
}
#endif /* __ASM_ARCH_DMA_H */

View File

@ -7,9 +7,11 @@ struct spi_device;
* struct ep93xx_spi_info - EP93xx specific SPI descriptor
* @num_chipselect: number of chip selects on this board, must be
* at least one
* @use_dma: use DMA for the transfers
*/
struct ep93xx_spi_info {
int num_chipselect;
bool use_dma;
};
/**

View File

@ -282,9 +282,10 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("mxc-ehci.2", "usb", usbotg_clk)
_REGISTER_CLOCK("fsl-usb2-udc", "usb", usbotg_clk)
_REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
_REGISTER_CLOCK("imx25-cspi.0", NULL, cspi1_clk)
_REGISTER_CLOCK("imx25-cspi.1", NULL, cspi2_clk)
_REGISTER_CLOCK("imx25-cspi.2", NULL, cspi3_clk)
/* i.mx25 has the i.mx35 type cspi */
_REGISTER_CLOCK("imx35-cspi.0", NULL, cspi1_clk)
_REGISTER_CLOCK("imx35-cspi.1", NULL, cspi2_clk)
_REGISTER_CLOCK("imx35-cspi.2", NULL, cspi3_clk)
_REGISTER_CLOCK("mxc_pwm.0", NULL, pwm1_clk)
_REGISTER_CLOCK("mxc_pwm.1", NULL, pwm2_clk)
_REGISTER_CLOCK("mxc_pwm.2", NULL, pwm3_clk)

View File

@ -1442,7 +1442,8 @@ static struct clk_lookup mx51_lookups[] = {
_REGISTER_CLOCK(NULL, "gpt_32k", gpt_32k_clk)
_REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk)
_REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
_REGISTER_CLOCK("imx51-cspi.0", NULL, cspi_clk)
/* i.mx51 has the i.mx35 type cspi */
_REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.0", NULL, esdhc1_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_clk)
@ -1471,9 +1472,11 @@ static struct clk_lookup mx53_lookups[] = {
_REGISTER_CLOCK("sdhci-esdhc-imx.1", NULL, esdhc2_mx53_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.2", NULL, esdhc3_mx53_clk)
_REGISTER_CLOCK("sdhci-esdhc-imx.3", NULL, esdhc4_mx53_clk)
_REGISTER_CLOCK("imx53-ecspi.0", NULL, ecspi1_clk)
_REGISTER_CLOCK("imx53-ecspi.1", NULL, ecspi2_clk)
_REGISTER_CLOCK("imx53-cspi.0", NULL, cspi_clk)
/* i.mx53 has the i.mx51 type ecspi */
_REGISTER_CLOCK("imx51-ecspi.0", NULL, ecspi1_clk)
_REGISTER_CLOCK("imx51-ecspi.1", NULL, ecspi2_clk)
/* i.mx53 has the i.mx25 type cspi */
_REGISTER_CLOCK("imx35-cspi.0", NULL, cspi_clk)
_REGISTER_CLOCK("imx2-wdt.0", NULL, dummy_clk)
_REGISTER_CLOCK("imx2-wdt.1", NULL, dummy_clk)
};

View File

@ -1,28 +0,0 @@
/* arch/arm/mach-s3c2410/include/mach/spi-gpio.h
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 - SPI Controller platform_device info
*
* 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.
*/
#ifndef __ASM_ARCH_SPIGPIO_H
#define __ASM_ARCH_SPIGPIO_H __FILE__
struct s3c2410_spigpio_info {
unsigned long pin_clk;
unsigned long pin_mosi;
unsigned long pin_miso;
int num_chipselect;
int bus_num;
void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs);
};
#endif /* __ASM_ARCH_SPIGPIO_H */

View File

@ -32,7 +32,7 @@
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/spi/spi_gpio.h>
#include <linux/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@ -53,8 +53,6 @@
#include <mach/fb.h>
#include <plat/nand.h>
#include <plat/udc.h>
#include <mach/spi.h>
#include <mach/spi-gpio.h>
#include <plat/iic.h>
#include <plat/common-smdk.h>
@ -216,32 +214,16 @@ static struct platform_device qt2410_led = {
/* SPI */
static void spi_gpio_cs(struct s3c2410_spigpio_info *spi, int cs)
{
switch (cs) {
case BITBANG_CS_ACTIVE:
gpio_set_value(S3C2410_GPB(5), 0);
break;
case BITBANG_CS_INACTIVE:
gpio_set_value(S3C2410_GPB(5), 1);
break;
}
}
static struct s3c2410_spigpio_info spi_gpio_cfg = {
.pin_clk = S3C2410_GPG(7),
.pin_mosi = S3C2410_GPG(6),
.pin_miso = S3C2410_GPG(5),
.chip_select = &spi_gpio_cs,
static struct spi_gpio_platform_data spi_gpio_cfg = {
.sck = S3C2410_GPG(7),
.mosi = S3C2410_GPG(6),
.miso = S3C2410_GPG(5),
};
static struct platform_device qt2410_spi = {
.name = "s3c24xx-spi-gpio",
.id = 1,
.dev = {
.platform_data = &spi_gpio_cfg,
},
.name = "spi-gpio",
.id = 1,
.dev.platform_data = &spi_gpio_cfg,
};
/* Board devices */

View File

@ -25,6 +25,7 @@
#include <video/ili9320.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_gpio.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@ -38,7 +39,6 @@
#include <mach/regs-gpio.h>
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/spi-gpio.h>
#include <mach/fb.h>
#include <asm/mach-types.h>
@ -389,45 +389,30 @@ static struct ili9320_platdata jive_lcm_config = {
/* LCD SPI support */
static void jive_lcd_spi_chipselect(struct s3c2410_spigpio_info *spi, int cs)
{
gpio_set_value(S3C2410_GPB(7), cs ? 0 : 1);
}
static struct s3c2410_spigpio_info jive_lcd_spi = {
.bus_num = 1,
.pin_clk = S3C2410_GPG(8),
.pin_mosi = S3C2410_GPB(8),
.num_chipselect = 1,
.chip_select = jive_lcd_spi_chipselect,
static struct spi_gpio_platform_data jive_lcd_spi = {
.sck = S3C2410_GPG(8),
.mosi = S3C2410_GPB(8),
.miso = SPI_GPIO_NO_MISO,
};
static struct platform_device jive_device_lcdspi = {
.name = "spi_s3c24xx_gpio",
.name = "spi-gpio",
.id = 1,
.num_resources = 0,
.dev.platform_data = &jive_lcd_spi,
};
/* WM8750 audio code SPI definition */
static void jive_wm8750_chipselect(struct s3c2410_spigpio_info *spi, int cs)
{
gpio_set_value(S3C2410_GPH(10), cs ? 0 : 1);
}
static struct s3c2410_spigpio_info jive_wm8750_spi = {
.bus_num = 2,
.pin_clk = S3C2410_GPB(4),
.pin_mosi = S3C2410_GPB(9),
.num_chipselect = 1,
.chip_select = jive_wm8750_chipselect,
static struct spi_gpio_platform_data jive_wm8750_spi = {
.sck = S3C2410_GPB(4),
.mosi = S3C2410_GPB(9),
.miso = SPI_GPIO_NO_MISO,
};
static struct platform_device jive_device_wm8750 = {
.name = "spi_s3c24xx_gpio",
.name = "spi-gpio",
.id = 2,
.num_resources = 0,
.dev.platform_data = &jive_wm8750_spi,
};
@ -441,12 +426,14 @@ static struct spi_board_info __initdata jive_spi_devs[] = {
.mode = SPI_MODE_3, /* CPOL=1, CPHA=1 */
.max_speed_hz = 100000,
.platform_data = &jive_lcm_config,
.controller_data = (void *)S3C2410_GPB(7),
}, {
.modalias = "WM8750",
.bus_num = 2,
.chip_select = 0,
.mode = SPI_MODE_0, /* CPOL=0, CPHA=0 */
.max_speed_hz = 100000,
.controller_data = (void *)S3C2410_GPH(10),
},
};

View File

@ -74,7 +74,6 @@
#include <mach/fb.h>
#include <mach/spi.h>
#include <mach/spi-gpio.h>
#include <plat/usb-control.h>
#include <mach/regs-mem.h>
#include <mach/hardware.h>

View File

@ -40,9 +40,10 @@ const struct imx_spi_imx_data imx21_cspi_data[] __initconst = {
#endif
#ifdef CONFIG_SOC_IMX25
/* i.mx25 has the i.mx35 type cspi */
const struct imx_spi_imx_data imx25_cspi_data[] __initconst = {
#define imx25_cspi_data_entry(_id, _hwid) \
imx_spi_imx_data_entry(MX25, CSPI, "imx25-cspi", _id, _hwid, SZ_16K)
imx_spi_imx_data_entry(MX25, CSPI, "imx35-cspi", _id, _hwid, SZ_16K)
imx25_cspi_data_entry(0, 1),
imx25_cspi_data_entry(1, 2),
imx25_cspi_data_entry(2, 3),
@ -79,8 +80,9 @@ const struct imx_spi_imx_data imx35_cspi_data[] __initconst = {
#endif /* ifdef CONFIG_SOC_IMX35 */
#ifdef CONFIG_SOC_IMX51
/* i.mx51 has the i.mx35 type cspi */
const struct imx_spi_imx_data imx51_cspi_data __initconst =
imx_spi_imx_data_entry_single(MX51, CSPI, "imx51-cspi", 2, , SZ_4K);
imx_spi_imx_data_entry_single(MX51, CSPI, "imx35-cspi", 2, , SZ_4K);
const struct imx_spi_imx_data imx51_ecspi_data[] __initconst = {
#define imx51_ecspi_data_entry(_id, _hwid) \
@ -91,12 +93,14 @@ const struct imx_spi_imx_data imx51_ecspi_data[] __initconst = {
#endif /* ifdef CONFIG_SOC_IMX51 */
#ifdef CONFIG_SOC_IMX53
/* i.mx53 has the i.mx35 type cspi */
const struct imx_spi_imx_data imx53_cspi_data __initconst =
imx_spi_imx_data_entry_single(MX53, CSPI, "imx53-cspi", 0, , SZ_4K);
imx_spi_imx_data_entry_single(MX53, CSPI, "imx35-cspi", 0, , SZ_4K);
/* i.mx53 has the i.mx51 type ecspi */
const struct imx_spi_imx_data imx53_ecspi_data[] __initconst = {
#define imx53_ecspi_data_entry(_id, _hwid) \
imx_spi_imx_data_entry(MX53, ECSPI, "imx53-ecspi", _id, _hwid, SZ_4K)
imx_spi_imx_data_entry(MX53, ECSPI, "imx51-ecspi", _id, _hwid, SZ_4K)
imx53_ecspi_data_entry(0, 1),
imx53_ecspi_data_entry(1, 2),
};

View File

@ -237,6 +237,13 @@ config MXS_DMA
Support the MXS DMA engine. This engine including APBH-DMA
and APBX-DMA is integrated into Freescale i.MX23/28 chips.
config EP93XX_DMA
bool "Cirrus Logic EP93xx DMA support"
depends on ARCH_EP93XX
select DMA_ENGINE
help
Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller.
config DMA_ENGINE
bool

View File

@ -25,3 +25,4 @@ obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
obj-$(CONFIG_PL330_DMA) += pl330.o
obj-$(CONFIG_PCH_DMA) += pch_dma.o
obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o
obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o

1355
drivers/dma/ep93xx_dma.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -86,9 +86,6 @@ config SPI_BFIN_SPORT
help
Enable support for a SPI bus via the Blackfin SPORT peripheral.
This driver can also be built as a module. If so, the module
will be called spi_bfin_sport.
config SPI_AU1550
tristate "Au1550/Au12x0 SPI Controller"
depends on (SOC_AU1550 || SOC_AU1200) && EXPERIMENTAL
@ -97,9 +94,6 @@ config SPI_AU1550
If you say yes to this option, support will be included for the
Au1550 SPI controller (may also work with Au1200,Au1210,Au1250).
This driver can also be built as a module. If so, the module
will be called au1550_spi.
config SPI_BITBANG
tristate "Utilities for Bitbanging SPI masters"
help
@ -130,9 +124,6 @@ config SPI_COLDFIRE_QSPI
This enables support for the Coldfire QSPI controller in master
mode.
This driver can also be built as a module. If so, the module
will be called coldfire_qspi.
config SPI_DAVINCI
tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller"
depends on SPI_MASTER && ARCH_DAVINCI
@ -140,9 +131,6 @@ config SPI_DAVINCI
help
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
tristate "Cirrus Logic EP93xx SPI controller"
depends on ARCH_EP93XX
@ -150,9 +138,6 @@ config SPI_EP93XX
This enables using the Cirrus EP93xx SPI controller in master
mode.
To compile this driver as a module, choose M here. The module will be
called ep93xx_spi.
config SPI_GPIO
tristate "GPIO-based bitbanging SPI Master"
depends on GENERIC_GPIO
@ -169,21 +154,6 @@ config SPI_GPIO
GPIO operations, you should be able to leverage that for better
speed with a custom version of this driver; see the source code.
config SPI_IMX_VER_IMX1
def_bool y if SOC_IMX1
config SPI_IMX_VER_0_0
def_bool y if SOC_IMX21 || SOC_IMX27
config SPI_IMX_VER_0_4
def_bool y if SOC_IMX31
config SPI_IMX_VER_0_7
def_bool y if ARCH_MX25 || SOC_IMX35 || SOC_IMX51 || SOC_IMX53
config SPI_IMX_VER_2_3
def_bool y if SOC_IMX51 || SOC_IMX53
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC
@ -328,16 +298,6 @@ config SPI_S3C24XX_FIQ
no free DMA channels, or when doing transfers that required both
TX and RX data paths.
config SPI_S3C24XX_GPIO
tristate "Samsung S3C24XX series SPI by GPIO"
depends on ARCH_S3C2410 && EXPERIMENTAL
select SPI_BITBANG
help
SPI driver for Samsung S3C24XX series ARM SoCs using
GPIO lines to provide the SPI bus. This can be used where
the inbuilt hardware cannot provide the transfer mode, or
where the board is using non hardware connected pins.
config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI"
depends on (ARCH_S3C64XX || ARCH_S5P64X0)
@ -385,16 +345,16 @@ config SPI_TI_SSP
This selects an SPI master implementation using a TI sequencer
serial port.
To compile this driver as a module, choose M here: the
module will be called ti-ssp-spi.
config SPI_TOPCLIFF_PCH
tristate "Topcliff PCH SPI Controller"
tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH SPI controller"
depends on PCI
help
SPI driver for the Topcliff PCH (Platform Controller Hub) SPI bus
used in some x86 embedded processors.
This driver also supports the ML7213, a companion chip for the
Atom E6xx series and compatible with the Intel EG20T PCH.
config SPI_TXX9
tristate "Toshiba TXx9 SPI controller"
depends on GENERIC_GPIO && CPU_TX49XX

View File

@ -7,68 +7,55 @@ ccflags-$(CONFIG_SPI_DEBUG) := -DDEBUG
# small core, mostly translating board-specific
# config declarations into driver model code
obj-$(CONFIG_SPI_MASTER) += spi.o
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
# SPI master controller drivers (bus)
obj-$(CONFIG_SPI_ALTERA) += spi_altera.o
obj-$(CONFIG_SPI_ATMEL) += atmel_spi.o
obj-$(CONFIG_SPI_ATH79) += ath79_spi.o
obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi_bfin_sport.o
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += coldfire_qspi.o
obj-$(CONFIG_SPI_DAVINCI) += davinci_spi.o
obj-$(CONFIG_SPI_DESIGNWARE) += dw_spi.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_EP93XX) += ep93xx_spi.o
obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += pxa2xx_spi_pci.o
obj-$(CONFIG_SPI_OC_TINY) += spi_oc_tiny.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += omap_uwire.o
obj-$(CONFIG_SPI_OMAP24XX) += omap2_mcspi.o
obj-$(CONFIG_SPI_OMAP_100K) += omap_spi_100k.o
obj-$(CONFIG_SPI_ORION) += orion_spi.o
obj-$(CONFIG_SPI_PL022) += amba-pl022.o
obj-$(CONFIG_SPI_MPC512x_PSC) += mpc512x_psc_spi.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += mpc52xx_psc_spi.o
obj-$(CONFIG_SPI_MPC52xx) += mpc52xx_spi.o
obj-$(CONFIG_SPI_FSL_LIB) += spi_fsl_lib.o
obj-$(CONFIG_SPI_FSL_ESPI) += spi_fsl_espi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi_fsl_spi.o
obj-$(CONFIG_SPI_PPC4xx) += spi_ppc4xx.o
obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o
obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx_hw.o
obj-$(CONFIG_SPI_S3C64XX) += spi_s3c64xx.o
obj-$(CONFIG_SPI_TEGRA) += spi_tegra.o
obj-$(CONFIG_SPI_TI_SSP) += ti-ssp-spi.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi_topcliff_pch.o
obj-$(CONFIG_SPI_TXX9) += spi_txx9.o
obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o
obj-$(CONFIG_SPI_SH) += spi_sh.o
obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_msiof.o
obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
obj-$(CONFIG_SPI_ALTERA) += spi-altera.o
obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx.o
obj-$(CONFIG_SPI_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
spi-dw-midpci-objs := spi-dw-pci.o spi-dw-mid.o
obj-$(CONFIG_SPI_EP93XX) += spi-ep93xx.o
obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
obj-$(CONFIG_SPI_IMX) += spi-imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o
obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o
obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o
obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o
obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o
obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022) += spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx) += spi-ppc4xx.o
obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx.o
obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o
spi-s3c24xx-hw-y := spi-s3c24xx.o
spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o
obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o
obj-$(CONFIG_SPI_SH) += spi-sh.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_STMP3XXX) += spi-stmp.o
obj-$(CONFIG_SPI_TEGRA) += spi-tegra.o
obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o
obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o
obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o
obj-$(CONFIG_SPI_TXX9) += spi-txx9.o
obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o
# special build for s3c24xx spi driver with fiq support
spi_s3c24xx_hw-y := spi_s3c24xx.o
spi_s3c24xx_hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi_s3c24xx_fiq.o
# ... add above this line ...
# SPI protocol drivers (device/link on bus)
obj-$(CONFIG_SPI_SPIDEV) += spidev.o
obj-$(CONFIG_SPI_TLE62X0) += tle62x0.o
# ... add above this line ...
# SPI slave controller drivers (upstream link)
# ... add above this line ...
# SPI slave drivers (protocol for that link)
# ... add above this line ...

View File

@ -1,167 +0,0 @@
/*
* Register definitions for Atmel Serial Peripheral Interface (SPI)
*
* Copyright (C) 2006 Atmel 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.
*/
#ifndef __ATMEL_SPI_H__
#define __ATMEL_SPI_H__
/* SPI register offsets */
#define SPI_CR 0x0000
#define SPI_MR 0x0004
#define SPI_RDR 0x0008
#define SPI_TDR 0x000c
#define SPI_SR 0x0010
#define SPI_IER 0x0014
#define SPI_IDR 0x0018
#define SPI_IMR 0x001c
#define SPI_CSR0 0x0030
#define SPI_CSR1 0x0034
#define SPI_CSR2 0x0038
#define SPI_CSR3 0x003c
#define SPI_RPR 0x0100
#define SPI_RCR 0x0104
#define SPI_TPR 0x0108
#define SPI_TCR 0x010c
#define SPI_RNPR 0x0110
#define SPI_RNCR 0x0114
#define SPI_TNPR 0x0118
#define SPI_TNCR 0x011c
#define SPI_PTCR 0x0120
#define SPI_PTSR 0x0124
/* Bitfields in CR */
#define SPI_SPIEN_OFFSET 0
#define SPI_SPIEN_SIZE 1
#define SPI_SPIDIS_OFFSET 1
#define SPI_SPIDIS_SIZE 1
#define SPI_SWRST_OFFSET 7
#define SPI_SWRST_SIZE 1
#define SPI_LASTXFER_OFFSET 24
#define SPI_LASTXFER_SIZE 1
/* Bitfields in MR */
#define SPI_MSTR_OFFSET 0
#define SPI_MSTR_SIZE 1
#define SPI_PS_OFFSET 1
#define SPI_PS_SIZE 1
#define SPI_PCSDEC_OFFSET 2
#define SPI_PCSDEC_SIZE 1
#define SPI_FDIV_OFFSET 3
#define SPI_FDIV_SIZE 1
#define SPI_MODFDIS_OFFSET 4
#define SPI_MODFDIS_SIZE 1
#define SPI_LLB_OFFSET 7
#define SPI_LLB_SIZE 1
#define SPI_PCS_OFFSET 16
#define SPI_PCS_SIZE 4
#define SPI_DLYBCS_OFFSET 24
#define SPI_DLYBCS_SIZE 8
/* Bitfields in RDR */
#define SPI_RD_OFFSET 0
#define SPI_RD_SIZE 16
/* Bitfields in TDR */
#define SPI_TD_OFFSET 0
#define SPI_TD_SIZE 16
/* Bitfields in SR */
#define SPI_RDRF_OFFSET 0
#define SPI_RDRF_SIZE 1
#define SPI_TDRE_OFFSET 1
#define SPI_TDRE_SIZE 1
#define SPI_MODF_OFFSET 2
#define SPI_MODF_SIZE 1
#define SPI_OVRES_OFFSET 3
#define SPI_OVRES_SIZE 1
#define SPI_ENDRX_OFFSET 4
#define SPI_ENDRX_SIZE 1
#define SPI_ENDTX_OFFSET 5
#define SPI_ENDTX_SIZE 1
#define SPI_RXBUFF_OFFSET 6
#define SPI_RXBUFF_SIZE 1
#define SPI_TXBUFE_OFFSET 7
#define SPI_TXBUFE_SIZE 1
#define SPI_NSSR_OFFSET 8
#define SPI_NSSR_SIZE 1
#define SPI_TXEMPTY_OFFSET 9
#define SPI_TXEMPTY_SIZE 1
#define SPI_SPIENS_OFFSET 16
#define SPI_SPIENS_SIZE 1
/* Bitfields in CSR0 */
#define SPI_CPOL_OFFSET 0
#define SPI_CPOL_SIZE 1
#define SPI_NCPHA_OFFSET 1
#define SPI_NCPHA_SIZE 1
#define SPI_CSAAT_OFFSET 3
#define SPI_CSAAT_SIZE 1
#define SPI_BITS_OFFSET 4
#define SPI_BITS_SIZE 4
#define SPI_SCBR_OFFSET 8
#define SPI_SCBR_SIZE 8
#define SPI_DLYBS_OFFSET 16
#define SPI_DLYBS_SIZE 8
#define SPI_DLYBCT_OFFSET 24
#define SPI_DLYBCT_SIZE 8
/* Bitfields in RCR */
#define SPI_RXCTR_OFFSET 0
#define SPI_RXCTR_SIZE 16
/* Bitfields in TCR */
#define SPI_TXCTR_OFFSET 0
#define SPI_TXCTR_SIZE 16
/* Bitfields in RNCR */
#define SPI_RXNCR_OFFSET 0
#define SPI_RXNCR_SIZE 16
/* Bitfields in TNCR */
#define SPI_TXNCR_OFFSET 0
#define SPI_TXNCR_SIZE 16
/* Bitfields in PTCR */
#define SPI_RXTEN_OFFSET 0
#define SPI_RXTEN_SIZE 1
#define SPI_RXTDIS_OFFSET 1
#define SPI_RXTDIS_SIZE 1
#define SPI_TXTEN_OFFSET 8
#define SPI_TXTEN_SIZE 1
#define SPI_TXTDIS_OFFSET 9
#define SPI_TXTDIS_SIZE 1
/* Constants for BITS */
#define SPI_BITS_8_BPT 0
#define SPI_BITS_9_BPT 1
#define SPI_BITS_10_BPT 2
#define SPI_BITS_11_BPT 3
#define SPI_BITS_12_BPT 4
#define SPI_BITS_13_BPT 5
#define SPI_BITS_14_BPT 6
#define SPI_BITS_15_BPT 7
#define SPI_BITS_16_BPT 8
/* Bit manipulation macros */
#define SPI_BIT(name) \
(1 << SPI_##name##_OFFSET)
#define SPI_BF(name,value) \
(((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
#define SPI_BFEXT(name,value) \
(((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
#define SPI_BFINS(name,value,old) \
( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
| SPI_BF(name,value))
/* Register access macros */
#define spi_readl(port,reg) \
__raw_readl((port)->regs + SPI_##reg)
#define spi_writel(port,reg,value) \
__raw_writel((value), (port)->regs + SPI_##reg)
#endif /* __ATMEL_SPI_H__ */

View File

@ -232,7 +232,7 @@ static __devinit int ath79_spi_probe(struct platform_device *pdev)
goto err_put_master;
}
sp->base = ioremap(r->start, r->end - r->start + 1);
sp->base = ioremap(r->start, resource_size(r));
if (!sp->base) {
ret = -ENXIO;
goto err_put_master;

View File

@ -25,7 +25,160 @@
#include <mach/gpio.h>
#include <mach/cpu.h>
#include "atmel_spi.h"
/* SPI register offsets */
#define SPI_CR 0x0000
#define SPI_MR 0x0004
#define SPI_RDR 0x0008
#define SPI_TDR 0x000c
#define SPI_SR 0x0010
#define SPI_IER 0x0014
#define SPI_IDR 0x0018
#define SPI_IMR 0x001c
#define SPI_CSR0 0x0030
#define SPI_CSR1 0x0034
#define SPI_CSR2 0x0038
#define SPI_CSR3 0x003c
#define SPI_RPR 0x0100
#define SPI_RCR 0x0104
#define SPI_TPR 0x0108
#define SPI_TCR 0x010c
#define SPI_RNPR 0x0110
#define SPI_RNCR 0x0114
#define SPI_TNPR 0x0118
#define SPI_TNCR 0x011c
#define SPI_PTCR 0x0120
#define SPI_PTSR 0x0124
/* Bitfields in CR */
#define SPI_SPIEN_OFFSET 0
#define SPI_SPIEN_SIZE 1
#define SPI_SPIDIS_OFFSET 1
#define SPI_SPIDIS_SIZE 1
#define SPI_SWRST_OFFSET 7
#define SPI_SWRST_SIZE 1
#define SPI_LASTXFER_OFFSET 24
#define SPI_LASTXFER_SIZE 1
/* Bitfields in MR */
#define SPI_MSTR_OFFSET 0
#define SPI_MSTR_SIZE 1
#define SPI_PS_OFFSET 1
#define SPI_PS_SIZE 1
#define SPI_PCSDEC_OFFSET 2
#define SPI_PCSDEC_SIZE 1
#define SPI_FDIV_OFFSET 3
#define SPI_FDIV_SIZE 1
#define SPI_MODFDIS_OFFSET 4
#define SPI_MODFDIS_SIZE 1
#define SPI_LLB_OFFSET 7
#define SPI_LLB_SIZE 1
#define SPI_PCS_OFFSET 16
#define SPI_PCS_SIZE 4
#define SPI_DLYBCS_OFFSET 24
#define SPI_DLYBCS_SIZE 8
/* Bitfields in RDR */
#define SPI_RD_OFFSET 0
#define SPI_RD_SIZE 16
/* Bitfields in TDR */
#define SPI_TD_OFFSET 0
#define SPI_TD_SIZE 16
/* Bitfields in SR */
#define SPI_RDRF_OFFSET 0
#define SPI_RDRF_SIZE 1
#define SPI_TDRE_OFFSET 1
#define SPI_TDRE_SIZE 1
#define SPI_MODF_OFFSET 2
#define SPI_MODF_SIZE 1
#define SPI_OVRES_OFFSET 3
#define SPI_OVRES_SIZE 1
#define SPI_ENDRX_OFFSET 4
#define SPI_ENDRX_SIZE 1
#define SPI_ENDTX_OFFSET 5
#define SPI_ENDTX_SIZE 1
#define SPI_RXBUFF_OFFSET 6
#define SPI_RXBUFF_SIZE 1
#define SPI_TXBUFE_OFFSET 7
#define SPI_TXBUFE_SIZE 1
#define SPI_NSSR_OFFSET 8
#define SPI_NSSR_SIZE 1
#define SPI_TXEMPTY_OFFSET 9
#define SPI_TXEMPTY_SIZE 1
#define SPI_SPIENS_OFFSET 16
#define SPI_SPIENS_SIZE 1
/* Bitfields in CSR0 */
#define SPI_CPOL_OFFSET 0
#define SPI_CPOL_SIZE 1
#define SPI_NCPHA_OFFSET 1
#define SPI_NCPHA_SIZE 1
#define SPI_CSAAT_OFFSET 3
#define SPI_CSAAT_SIZE 1
#define SPI_BITS_OFFSET 4
#define SPI_BITS_SIZE 4
#define SPI_SCBR_OFFSET 8
#define SPI_SCBR_SIZE 8
#define SPI_DLYBS_OFFSET 16
#define SPI_DLYBS_SIZE 8
#define SPI_DLYBCT_OFFSET 24
#define SPI_DLYBCT_SIZE 8
/* Bitfields in RCR */
#define SPI_RXCTR_OFFSET 0
#define SPI_RXCTR_SIZE 16
/* Bitfields in TCR */
#define SPI_TXCTR_OFFSET 0
#define SPI_TXCTR_SIZE 16
/* Bitfields in RNCR */
#define SPI_RXNCR_OFFSET 0
#define SPI_RXNCR_SIZE 16
/* Bitfields in TNCR */
#define SPI_TXNCR_OFFSET 0
#define SPI_TXNCR_SIZE 16
/* Bitfields in PTCR */
#define SPI_RXTEN_OFFSET 0
#define SPI_RXTEN_SIZE 1
#define SPI_RXTDIS_OFFSET 1
#define SPI_RXTDIS_SIZE 1
#define SPI_TXTEN_OFFSET 8
#define SPI_TXTEN_SIZE 1
#define SPI_TXTDIS_OFFSET 9
#define SPI_TXTDIS_SIZE 1
/* Constants for BITS */
#define SPI_BITS_8_BPT 0
#define SPI_BITS_9_BPT 1
#define SPI_BITS_10_BPT 2
#define SPI_BITS_11_BPT 3
#define SPI_BITS_12_BPT 4
#define SPI_BITS_13_BPT 5
#define SPI_BITS_14_BPT 6
#define SPI_BITS_15_BPT 7
#define SPI_BITS_16_BPT 8
/* Bit manipulation macros */
#define SPI_BIT(name) \
(1 << SPI_##name##_OFFSET)
#define SPI_BF(name,value) \
(((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
#define SPI_BFEXT(name,value) \
(((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
#define SPI_BFINS(name,value,old) \
( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
| SPI_BF(name,value))
/* Register access macros */
#define spi_readl(port,reg) \
__raw_readl((port)->regs + SPI_##reg)
#define spi_writel(port,reg,value) \
__raw_writel((value), (port)->regs + SPI_##reg)
/*
* The core SPI transfer engine just talks to a register bank to set up

View File

@ -1,5 +1,5 @@
/*
* au1550_spi.c - au1550 psc spi controller driver
* au1550 psc spi controller driver
* may work also with au1200, au1210, au1250
* will not work on au1000, au1100 and au1500 (no full spi controller there)
*

View File

@ -58,7 +58,7 @@ struct bfin_spi_master_data {
struct spi_master *master;
/* Regs base of SPI controller */
void __iomem *regs_base;
struct bfin_spi_regs __iomem *regs;
/* Pin request list */
u16 *pin_req;
@ -122,34 +122,14 @@ struct bfin_spi_slave_data {
const struct bfin_spi_transfer_ops *ops;
};
#define DEFINE_SPI_REG(reg, off) \
static inline u16 read_##reg(struct bfin_spi_master_data *drv_data) \
{ return bfin_read16(drv_data->regs_base + off); } \
static inline void write_##reg(struct bfin_spi_master_data *drv_data, u16 v) \
{ bfin_write16(drv_data->regs_base + off, v); }
DEFINE_SPI_REG(CTRL, 0x00)
DEFINE_SPI_REG(FLAG, 0x04)
DEFINE_SPI_REG(STAT, 0x08)
DEFINE_SPI_REG(TDBR, 0x0C)
DEFINE_SPI_REG(RDBR, 0x10)
DEFINE_SPI_REG(BAUD, 0x14)
DEFINE_SPI_REG(SHAW, 0x18)
static void bfin_spi_enable(struct bfin_spi_master_data *drv_data)
{
u16 cr;
cr = read_CTRL(drv_data);
write_CTRL(drv_data, (cr | BIT_CTL_ENABLE));
bfin_write_or(&drv_data->regs->ctl, BIT_CTL_ENABLE);
}
static void bfin_spi_disable(struct bfin_spi_master_data *drv_data)
{
u16 cr;
cr = read_CTRL(drv_data);
write_CTRL(drv_data, (cr & (~BIT_CTL_ENABLE)));
bfin_write_and(&drv_data->regs->ctl, ~BIT_CTL_ENABLE);
}
/* Caculate the SPI_BAUD register value based on input HZ */
@ -172,10 +152,10 @@ static int bfin_spi_flush(struct bfin_spi_master_data *drv_data)
unsigned long limit = loops_per_jiffy << 1;
/* wait for stop and clear stat */
while (!(read_STAT(drv_data) & BIT_STAT_SPIF) && --limit)
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF) && --limit)
cpu_relax();
write_STAT(drv_data, BIT_STAT_CLR);
bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
return limit;
}
@ -183,29 +163,19 @@ static int bfin_spi_flush(struct bfin_spi_master_data *drv_data)
/* Chip select operation functions for cs_change flag */
static void bfin_spi_cs_active(struct bfin_spi_master_data *drv_data, struct bfin_spi_slave_data *chip)
{
if (likely(chip->chip_select_num < MAX_CTRL_CS)) {
u16 flag = read_FLAG(drv_data);
flag &= ~chip->flag;
write_FLAG(drv_data, flag);
} else {
if (likely(chip->chip_select_num < MAX_CTRL_CS))
bfin_write_and(&drv_data->regs->flg, ~chip->flag);
else
gpio_set_value(chip->cs_gpio, 0);
}
}
static void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data,
struct bfin_spi_slave_data *chip)
{
if (likely(chip->chip_select_num < MAX_CTRL_CS)) {
u16 flag = read_FLAG(drv_data);
flag |= chip->flag;
write_FLAG(drv_data, flag);
} else {
if (likely(chip->chip_select_num < MAX_CTRL_CS))
bfin_write_or(&drv_data->regs->flg, chip->flag);
else
gpio_set_value(chip->cs_gpio, 1);
}
/* Move delay here for consistency */
if (chip->cs_chg_udelay)
@ -216,25 +186,15 @@ static void bfin_spi_cs_deactive(struct bfin_spi_master_data *drv_data,
static inline void bfin_spi_cs_enable(struct bfin_spi_master_data *drv_data,
struct bfin_spi_slave_data *chip)
{
if (chip->chip_select_num < MAX_CTRL_CS) {
u16 flag = read_FLAG(drv_data);
flag |= (chip->flag >> 8);
write_FLAG(drv_data, flag);
}
if (chip->chip_select_num < MAX_CTRL_CS)
bfin_write_or(&drv_data->regs->flg, chip->flag >> 8);
}
static inline void bfin_spi_cs_disable(struct bfin_spi_master_data *drv_data,
struct bfin_spi_slave_data *chip)
{
if (chip->chip_select_num < MAX_CTRL_CS) {
u16 flag = read_FLAG(drv_data);
flag &= ~(chip->flag >> 8);
write_FLAG(drv_data, flag);
}
if (chip->chip_select_num < MAX_CTRL_CS)
bfin_write_and(&drv_data->regs->flg, ~(chip->flag >> 8));
}
/* stop controller and re-config current chip*/
@ -243,15 +203,15 @@ static void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data)
struct bfin_spi_slave_data *chip = drv_data->cur_chip;
/* Clear status and disable clock */
write_STAT(drv_data, BIT_STAT_CLR);
bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
bfin_spi_disable(drv_data);
dev_dbg(&drv_data->pdev->dev, "restoring spi ctl state\n");
SSYNC();
/* Load the registers */
write_CTRL(drv_data, chip->ctl_reg);
write_BAUD(drv_data, chip->baud);
bfin_write(&drv_data->regs->ctl, chip->ctl_reg);
bfin_write(&drv_data->regs->baud, chip->baud);
bfin_spi_enable(drv_data);
bfin_spi_cs_active(drv_data, chip);
@ -260,7 +220,7 @@ static void bfin_spi_restore_state(struct bfin_spi_master_data *drv_data)
/* used to kick off transfer in rx mode and read unwanted RX data */
static inline void bfin_spi_dummy_read(struct bfin_spi_master_data *drv_data)
{
(void) read_RDBR(drv_data);
(void) bfin_read(&drv_data->regs->rdbr);
}
static void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data)
@ -269,10 +229,10 @@ static void bfin_spi_u8_writer(struct bfin_spi_master_data *drv_data)
bfin_spi_dummy_read(drv_data);
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
bfin_write(&drv_data->regs->tdbr, (*(u8 *) (drv_data->tx++)));
/* wait until transfer finished.
checking SPIF or TXS may not guarantee transfer completion */
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
cpu_relax();
/* discard RX data and clear RXS */
bfin_spi_dummy_read(drv_data);
@ -287,10 +247,10 @@ static void bfin_spi_u8_reader(struct bfin_spi_master_data *drv_data)
bfin_spi_dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(drv_data, tx_val);
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
bfin_write(&drv_data->regs->tdbr, tx_val);
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
cpu_relax();
*(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
*(u8 *) (drv_data->rx++) = bfin_read(&drv_data->regs->rdbr);
}
}
@ -300,10 +260,10 @@ static void bfin_spi_u8_duplex(struct bfin_spi_master_data *drv_data)
bfin_spi_dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(drv_data, (*(u8 *) (drv_data->tx++)));
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
bfin_write(&drv_data->regs->tdbr, (*(u8 *) (drv_data->tx++)));
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
cpu_relax();
*(u8 *) (drv_data->rx++) = read_RDBR(drv_data);
*(u8 *) (drv_data->rx++) = bfin_read(&drv_data->regs->rdbr);
}
}
@ -319,11 +279,11 @@ static void bfin_spi_u16_writer(struct bfin_spi_master_data *drv_data)
bfin_spi_dummy_read(drv_data);
while (drv_data->tx < drv_data->tx_end) {
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
bfin_write(&drv_data->regs->tdbr, (*(u16 *) (drv_data->tx)));
drv_data->tx += 2;
/* wait until transfer finished.
checking SPIF or TXS may not guarantee transfer completion */
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
cpu_relax();
/* discard RX data and clear RXS */
bfin_spi_dummy_read(drv_data);
@ -338,10 +298,10 @@ static void bfin_spi_u16_reader(struct bfin_spi_master_data *drv_data)
bfin_spi_dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(drv_data, tx_val);
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
bfin_write(&drv_data->regs->tdbr, tx_val);
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
cpu_relax();
*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
*(u16 *) (drv_data->rx) = bfin_read(&drv_data->regs->rdbr);
drv_data->rx += 2;
}
}
@ -352,11 +312,11 @@ static void bfin_spi_u16_duplex(struct bfin_spi_master_data *drv_data)
bfin_spi_dummy_read(drv_data);
while (drv_data->rx < drv_data->rx_end) {
write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
bfin_write(&drv_data->regs->tdbr, (*(u16 *) (drv_data->tx)));
drv_data->tx += 2;
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
cpu_relax();
*(u16 *) (drv_data->rx) = read_RDBR(drv_data);
*(u16 *) (drv_data->rx) = bfin_read(&drv_data->regs->rdbr);
drv_data->rx += 2;
}
}
@ -428,7 +388,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
int loop = 0;
/* wait until transfer finished. */
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_RXS))
cpu_relax();
if ((drv_data->tx && drv_data->tx >= drv_data->tx_end) ||
@ -439,11 +399,11 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
if (n_bytes % 2) {
u16 *buf = (u16 *)drv_data->rx;
for (loop = 0; loop < n_bytes / 2; loop++)
*buf++ = read_RDBR(drv_data);
*buf++ = bfin_read(&drv_data->regs->rdbr);
} else {
u8 *buf = (u8 *)drv_data->rx;
for (loop = 0; loop < n_bytes; loop++)
*buf++ = read_RDBR(drv_data);
*buf++ = bfin_read(&drv_data->regs->rdbr);
}
drv_data->rx += n_bytes;
}
@ -468,15 +428,15 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
u16 *buf = (u16 *)drv_data->rx;
u16 *buf2 = (u16 *)drv_data->tx;
for (loop = 0; loop < n_bytes / 2; loop++) {
*buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, *buf2++);
*buf++ = bfin_read(&drv_data->regs->rdbr);
bfin_write(&drv_data->regs->tdbr, *buf2++);
}
} else {
u8 *buf = (u8 *)drv_data->rx;
u8 *buf2 = (u8 *)drv_data->tx;
for (loop = 0; loop < n_bytes; loop++) {
*buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, *buf2++);
*buf++ = bfin_read(&drv_data->regs->rdbr);
bfin_write(&drv_data->regs->tdbr, *buf2++);
}
}
} else if (drv_data->rx) {
@ -485,14 +445,14 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
if (n_bytes % 2) {
u16 *buf = (u16 *)drv_data->rx;
for (loop = 0; loop < n_bytes / 2; loop++) {
*buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, chip->idle_tx_val);
*buf++ = bfin_read(&drv_data->regs->rdbr);
bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
}
} else {
u8 *buf = (u8 *)drv_data->rx;
for (loop = 0; loop < n_bytes; loop++) {
*buf++ = read_RDBR(drv_data);
write_TDBR(drv_data, chip->idle_tx_val);
*buf++ = bfin_read(&drv_data->regs->rdbr);
bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
}
}
} else if (drv_data->tx) {
@ -501,14 +461,14 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
if (n_bytes % 2) {
u16 *buf = (u16 *)drv_data->tx;
for (loop = 0; loop < n_bytes / 2; loop++) {
read_RDBR(drv_data);
write_TDBR(drv_data, *buf++);
bfin_read(&drv_data->regs->rdbr);
bfin_write(&drv_data->regs->tdbr, *buf++);
}
} else {
u8 *buf = (u8 *)drv_data->tx;
for (loop = 0; loop < n_bytes; loop++) {
read_RDBR(drv_data);
write_TDBR(drv_data, *buf++);
bfin_read(&drv_data->regs->rdbr);
bfin_write(&drv_data->regs->tdbr, *buf++);
}
}
}
@ -528,19 +488,19 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
struct spi_message *msg = drv_data->cur_msg;
unsigned long timeout;
unsigned short dmastat = get_dma_curr_irqstat(drv_data->dma_channel);
u16 spistat = read_STAT(drv_data);
u16 spistat = bfin_read(&drv_data->regs->stat);
dev_dbg(&drv_data->pdev->dev,
"in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
dmastat, spistat);
if (drv_data->rx != NULL) {
u16 cr = read_CTRL(drv_data);
u16 cr = bfin_read(&drv_data->regs->ctl);
/* discard old RX data and clear RXS */
bfin_spi_dummy_read(drv_data);
write_CTRL(drv_data, cr & ~BIT_CTL_ENABLE); /* Disable SPI */
write_CTRL(drv_data, cr & ~BIT_CTL_TIMOD); /* Restore State */
write_STAT(drv_data, BIT_STAT_CLR); /* Clear Status */
bfin_write(&drv_data->regs->ctl, cr & ~BIT_CTL_ENABLE); /* Disable SPI */
bfin_write(&drv_data->regs->ctl, cr & ~BIT_CTL_TIMOD); /* Restore State */
bfin_write(&drv_data->regs->stat, BIT_STAT_CLR); /* Clear Status */
}
clear_dma_irqstat(drv_data->dma_channel);
@ -552,17 +512,17 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
* register until it goes low for 2 successive reads
*/
if (drv_data->tx != NULL) {
while ((read_STAT(drv_data) & BIT_STAT_TXS) ||
(read_STAT(drv_data) & BIT_STAT_TXS))
while ((bfin_read(&drv_data->regs->stat) & BIT_STAT_TXS) ||
(bfin_read(&drv_data->regs->stat) & BIT_STAT_TXS))
cpu_relax();
}
dev_dbg(&drv_data->pdev->dev,
"in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
dmastat, read_STAT(drv_data));
dmastat, bfin_read(&drv_data->regs->stat));
timeout = jiffies + HZ;
while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF))
if (!time_before(jiffies, timeout)) {
dev_warn(&drv_data->pdev->dev, "timeout waiting for SPIF");
break;
@ -699,9 +659,9 @@ static void bfin_spi_pump_transfers(unsigned long data)
bfin_spi_giveback(drv_data);
return;
}
cr = read_CTRL(drv_data) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
cr = bfin_read(&drv_data->regs->ctl) & ~(BIT_CTL_TIMOD | BIT_CTL_WORDSIZE);
cr |= cr_width;
write_CTRL(drv_data, cr);
bfin_write(&drv_data->regs->ctl, cr);
dev_dbg(&drv_data->pdev->dev,
"transfer: drv_data->ops is %p, chip->ops is %p, u8_ops is %p\n",
@ -712,11 +672,11 @@ static void bfin_spi_pump_transfers(unsigned long data)
/* Speed setup (surely valid because already checked) */
if (transfer->speed_hz)
write_BAUD(drv_data, hz_to_spi_baud(transfer->speed_hz));
bfin_write(&drv_data->regs->baud, hz_to_spi_baud(transfer->speed_hz));
else
write_BAUD(drv_data, chip->baud);
bfin_write(&drv_data->regs->baud, chip->baud);
write_STAT(drv_data, BIT_STAT_CLR);
bfin_write(&drv_data->regs->stat, BIT_STAT_CLR);
bfin_spi_cs_active(drv_data, chip);
dev_dbg(&drv_data->pdev->dev,
@ -749,7 +709,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
}
/* poll for SPI completion before start */
while (!(read_STAT(drv_data) & BIT_STAT_SPIF))
while (!(bfin_read(&drv_data->regs->stat) & BIT_STAT_SPIF))
cpu_relax();
/* dirty hack for autobuffer DMA mode */
@ -766,7 +726,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
enable_dma(drv_data->dma_channel);
/* start SPI transfer */
write_CTRL(drv_data, cr | BIT_CTL_TIMOD_DMA_TX);
bfin_write(&drv_data->regs->ctl, cr | BIT_CTL_TIMOD_DMA_TX);
/* just return here, there can only be one transfer
* in this mode
@ -821,7 +781,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
set_dma_config(drv_data->dma_channel, dma_config);
local_irq_save(flags);
SSYNC();
write_CTRL(drv_data, cr);
bfin_write(&drv_data->regs->ctl, cr);
enable_dma(drv_data->dma_channel);
dma_enable_irq(drv_data->dma_channel);
local_irq_restore(flags);
@ -835,7 +795,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
* problems with setting up the output value in TDBR prior to the
* start of the transfer.
*/
write_CTRL(drv_data, cr | BIT_CTL_TXMOD);
bfin_write(&drv_data->regs->ctl, cr | BIT_CTL_TXMOD);
if (chip->pio_interrupt) {
/* SPI irq should have been disabled by now */
@ -845,19 +805,19 @@ static void bfin_spi_pump_transfers(unsigned long data)
/* start transfer */
if (drv_data->tx == NULL)
write_TDBR(drv_data, chip->idle_tx_val);
bfin_write(&drv_data->regs->tdbr, chip->idle_tx_val);
else {
int loop;
if (bits_per_word % 16 == 0) {
u16 *buf = (u16 *)drv_data->tx;
for (loop = 0; loop < bits_per_word / 16;
loop++) {
write_TDBR(drv_data, *buf++);
bfin_write(&drv_data->regs->tdbr, *buf++);
}
} else if (bits_per_word % 8 == 0) {
u8 *buf = (u8 *)drv_data->tx;
for (loop = 0; loop < bits_per_word / 8; loop++)
write_TDBR(drv_data, *buf++);
bfin_write(&drv_data->regs->tdbr, *buf++);
}
drv_data->tx += drv_data->n_bytes;
@ -1005,7 +965,7 @@ static int bfin_spi_transfer(struct spi_device *spi, struct spi_message *msg)
#define MAX_SPI_SSEL 7
static u16 ssel[][MAX_SPI_SSEL] = {
static const u16 ssel[][MAX_SPI_SSEL] = {
{P_SPI0_SSEL1, P_SPI0_SSEL2, P_SPI0_SSEL3,
P_SPI0_SSEL4, P_SPI0_SSEL5,
P_SPI0_SSEL6, P_SPI0_SSEL7},
@ -1226,7 +1186,7 @@ static void bfin_spi_cleanup(struct spi_device *spi)
spi_set_ctldata(spi, NULL);
}
static inline int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
static int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
{
INIT_LIST_HEAD(&drv_data->queue);
spin_lock_init(&drv_data->lock);
@ -1248,7 +1208,7 @@ static inline int bfin_spi_init_queue(struct bfin_spi_master_data *drv_data)
return 0;
}
static inline int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
static int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
{
unsigned long flags;
@ -1270,7 +1230,7 @@ static inline int bfin_spi_start_queue(struct bfin_spi_master_data *drv_data)
return 0;
}
static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data)
static int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data)
{
unsigned long flags;
unsigned limit = 500;
@ -1299,7 +1259,7 @@ static inline int bfin_spi_stop_queue(struct bfin_spi_master_data *drv_data)
return status;
}
static inline int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
static int bfin_spi_destroy_queue(struct bfin_spi_master_data *drv_data)
{
int status;
@ -1353,8 +1313,8 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
goto out_error_get_res;
}
drv_data->regs_base = ioremap(res->start, resource_size(res));
if (drv_data->regs_base == NULL) {
drv_data->regs = ioremap(res->start, resource_size(res));
if (drv_data->regs == NULL) {
dev_err(dev, "Cannot map IO\n");
status = -ENXIO;
goto out_error_ioremap;
@ -1397,8 +1357,8 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
/* Reset SPI registers. If these registers were used by the boot loader,
* the sky may fall on your head if you enable the dma controller.
*/
write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER);
write_FLAG(drv_data, 0xFF00);
bfin_write(&drv_data->regs->ctl, BIT_CTL_CPHA | BIT_CTL_MASTER);
bfin_write(&drv_data->regs->flg, 0xFF00);
/* Register with the SPI framework */
platform_set_drvdata(pdev, drv_data);
@ -1408,15 +1368,15 @@ static int __init bfin_spi_probe(struct platform_device *pdev)
goto out_error_queue_alloc;
}
dev_info(dev, "%s, Version %s, regs_base@%p, dma channel@%d\n",
DRV_DESC, DRV_VERSION, drv_data->regs_base,
dev_info(dev, "%s, Version %s, regs@%p, dma channel@%d\n",
DRV_DESC, DRV_VERSION, drv_data->regs,
drv_data->dma_channel);
return status;
out_error_queue_alloc:
bfin_spi_destroy_queue(drv_data);
out_error_free_io:
iounmap((void *) drv_data->regs_base);
iounmap(drv_data->regs);
out_error_ioremap:
out_error_get_res:
spi_master_put(master);
@ -1473,14 +1433,14 @@ static int bfin_spi_suspend(struct platform_device *pdev, pm_message_t state)
if (status != 0)
return status;
drv_data->ctrl_reg = read_CTRL(drv_data);
drv_data->flag_reg = read_FLAG(drv_data);
drv_data->ctrl_reg = bfin_read(&drv_data->regs->ctl);
drv_data->flag_reg = bfin_read(&drv_data->regs->flg);
/*
* reset SPI_CTL and SPI_FLG registers
*/
write_CTRL(drv_data, BIT_CTL_CPHA | BIT_CTL_MASTER);
write_FLAG(drv_data, 0xFF00);
bfin_write(&drv_data->regs->ctl, BIT_CTL_CPHA | BIT_CTL_MASTER);
bfin_write(&drv_data->regs->flg, 0xFF00);
return 0;
}
@ -1490,8 +1450,8 @@ static int bfin_spi_resume(struct platform_device *pdev)
struct bfin_spi_master_data *drv_data = platform_get_drvdata(pdev);
int status = 0;
write_CTRL(drv_data, drv_data->ctrl_reg);
write_FLAG(drv_data, drv_data->flag_reg);
bfin_write(&drv_data->regs->ctl, drv_data->ctrl_reg);
bfin_write(&drv_data->regs->flg, drv_data->flag_reg);
/* Start the queue running */
status = bfin_spi_start_queue(drv_data);

View File

@ -1,5 +1,5 @@
/*
* spi_bitbang.c - polling/bitbanging SPI master controller driver utilities
* polling/bitbanging SPI master controller driver utilities
*
* 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
@ -68,7 +68,7 @@ static unsigned bitbang_txrx_8(
unsigned ns,
struct spi_transfer *t
) {
unsigned bits = spi->bits_per_word;
unsigned bits = t->bits_per_word ? : spi->bits_per_word;
unsigned count = t->len;
const u8 *tx = t->tx_buf;
u8 *rx = t->rx_buf;
@ -94,7 +94,7 @@ static unsigned bitbang_txrx_16(
unsigned ns,
struct spi_transfer *t
) {
unsigned bits = spi->bits_per_word;
unsigned bits = t->bits_per_word ? : spi->bits_per_word;
unsigned count = t->len;
const u16 *tx = t->tx_buf;
u16 *rx = t->rx_buf;
@ -120,7 +120,7 @@ static unsigned bitbang_txrx_32(
unsigned ns,
struct spi_transfer *t
) {
unsigned bits = spi->bits_per_word;
unsigned bits = t->bits_per_word ? : spi->bits_per_word;
unsigned count = t->len;
const u32 *tx = t->tx_buf;
u32 *rx = t->rx_buf;

View File

@ -1,5 +1,5 @@
/*
* spi_butterfly.c - parport-to-butterfly adapter
* parport-to-butterfly adapter
*
* Copyright (C) 2005 David Brownell
*
@ -149,7 +149,7 @@ static void butterfly_chipselect(struct spi_device *spi, int value)
#define spidelay(X) do{}while(0)
//#define spidelay ndelay
#include "spi_bitbang_txrx.h"
#include "spi-bitbang-txrx.h"
static u32
butterfly_txrx_word_mode0(struct spi_device *spi,

View File

@ -1,5 +1,5 @@
/*
* dw_spi_mid.c - special handling for DW core on Intel MID platform
* Special handling for DW core on Intel MID platform
*
* Copyright (c) 2009, Intel Corporation.
*
@ -23,7 +23,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include "dw_spi.h"
#include "spi-dw.h"
#ifdef CONFIG_SPI_DW_MID_DMA
#include <linux/intel_mid_dma.h>

View File

@ -1,5 +1,5 @@
/*
* dw_spi_mmio.c - Memory-mapped interface driver for DW SPI Core
* Memory-mapped interface driver for DW SPI Core
*
* Copyright (c) 2010, Octasic semiconductor.
*
@ -16,7 +16,7 @@
#include <linux/spi/spi.h>
#include <linux/scatterlist.h>
#include "dw_spi.h"
#include "spi-dw.h"
#define DRIVER_NAME "dw_spi_mmio"

View File

@ -1,5 +1,5 @@
/*
* dw_spi_pci.c - PCI interface driver for DW SPI Core
* PCI interface driver for DW SPI Core
*
* Copyright (c) 2009, Intel Corporation.
*
@ -22,7 +22,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include "dw_spi.h"
#include "spi-dw.h"
#define DRIVER_NAME "dw_spi_pci"

View File

@ -1,5 +1,5 @@
/*
* dw_spi.c - Designware SPI core controller driver (refer pxa2xx_spi.c)
* Designware SPI core controller driver (refer pxa2xx_spi.c)
*
* Copyright (c) 2009, Intel Corporation.
*
@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include "dw_spi.h"
#include "spi-dw.h"
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
@ -818,9 +818,11 @@ int __devinit dw_spi_add_host(struct dw_spi *dws)
dws->prev_chip = NULL;
dws->dma_inited = 0;
dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60);
snprintf(dws->name, sizeof(dws->name), "dw_spi%d",
dws->bus_num);
ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED,
"dw_spi", dws);
dws->name, dws);
if (ret < 0) {
dev_err(&master->dev, "can not get IRQ\n");
goto err_free_master;

View File

@ -96,6 +96,7 @@ struct dw_spi {
struct spi_device *cur_dev;
struct device *parent_dev;
enum dw_ssi_type type;
char name[16];
void __iomem *regs;
unsigned long paddr;

View File

@ -1,7 +1,7 @@
/*
* Driver for Cirrus Logic EP93xx SPI controller.
*
* Copyright (c) 2010 Mika Westerberg
* Copyright (C) 2010-2011 Mika Westerberg
*
* Explicit FIFO handling code was inspired by amba-pl022 driver.
*
@ -21,13 +21,16 @@
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/scatterlist.h>
#include <linux/spi/spi.h>
#include <mach/dma.h>
#include <mach/ep93xx_spi.h>
#define SSPCR0 0x0000
@ -71,6 +74,7 @@
* @pdev: pointer to platform device
* @clk: clock for the controller
* @regs_base: pointer to ioremap()'d registers
* @sspdr_phys: physical address of the SSPDR register
* @irq: IRQ number used by the driver
* @min_rate: minimum clock rate (in Hz) supported by the controller
* @max_rate: maximum clock rate (in Hz) supported by the controller
@ -84,6 +88,14 @@
* @rx: current byte in transfer to receive
* @fifo_level: how full is FIFO (%0..%SPI_FIFO_SIZE - %1). Receiving one
* frame decreases this level and sending one frame increases it.
* @dma_rx: RX DMA channel
* @dma_tx: TX DMA channel
* @dma_rx_data: RX parameters passed to the DMA engine
* @dma_tx_data: TX parameters passed to the DMA engine
* @rx_sgt: sg table for RX transfers
* @tx_sgt: sg table for TX transfers
* @zeropage: dummy page used as RX buffer when only TX buffer is passed in by
* the client
*
* This structure holds EP93xx SPI controller specific information. When
* @running is %true, driver accepts transfer requests from protocol drivers.
@ -100,6 +112,7 @@ struct ep93xx_spi {
const struct platform_device *pdev;
struct clk *clk;
void __iomem *regs_base;
unsigned long sspdr_phys;
int irq;
unsigned long min_rate;
unsigned long max_rate;
@ -112,6 +125,13 @@ struct ep93xx_spi {
size_t tx;
size_t rx;
size_t fifo_level;
struct dma_chan *dma_rx;
struct dma_chan *dma_tx;
struct ep93xx_dma_data dma_rx_data;
struct ep93xx_dma_data dma_tx_data;
struct sg_table rx_sgt;
struct sg_table tx_sgt;
void *zeropage;
};
/**
@ -496,14 +516,195 @@ static int ep93xx_spi_read_write(struct ep93xx_spi *espi)
espi->fifo_level++;
}
if (espi->rx == t->len) {
msg->actual_length += t->len;
if (espi->rx == t->len)
return 0;
}
return -EINPROGRESS;
}
static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi)
{
/*
* Now everything is set up for the current transfer. We prime the TX
* FIFO, enable interrupts, and wait for the transfer to complete.
*/
if (ep93xx_spi_read_write(espi)) {
ep93xx_spi_enable_interrupts(espi);
wait_for_completion(&espi->wait);
}
}
/**
* ep93xx_spi_dma_prepare() - prepares a DMA transfer
* @espi: ep93xx SPI controller struct
* @dir: DMA transfer direction
*
* Function configures the DMA, maps the buffer and prepares the DMA
* descriptor. Returns a valid DMA descriptor in case of success and ERR_PTR
* in case of failure.
*/
static struct dma_async_tx_descriptor *
ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
{
struct spi_transfer *t = espi->current_msg->state;
struct dma_async_tx_descriptor *txd;
enum dma_slave_buswidth buswidth;
struct dma_slave_config conf;
struct scatterlist *sg;
struct sg_table *sgt;
struct dma_chan *chan;
const void *buf, *pbuf;
size_t len = t->len;
int i, ret, nents;
if (bits_per_word(espi) > 8)
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
else
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE;
memset(&conf, 0, sizeof(conf));
conf.direction = dir;
if (dir == DMA_FROM_DEVICE) {
chan = espi->dma_rx;
buf = t->rx_buf;
sgt = &espi->rx_sgt;
conf.src_addr = espi->sspdr_phys;
conf.src_addr_width = buswidth;
} else {
chan = espi->dma_tx;
buf = t->tx_buf;
sgt = &espi->tx_sgt;
conf.dst_addr = espi->sspdr_phys;
conf.dst_addr_width = buswidth;
}
ret = dmaengine_slave_config(chan, &conf);
if (ret)
return ERR_PTR(ret);
/*
* We need to split the transfer into PAGE_SIZE'd chunks. This is
* because we are using @espi->zeropage to provide a zero RX buffer
* for the TX transfers and we have only allocated one page for that.
*
* For performance reasons we allocate a new sg_table only when
* needed. Otherwise we will re-use the current one. Eventually the
* last sg_table is released in ep93xx_spi_release_dma().
*/
nents = DIV_ROUND_UP(len, PAGE_SIZE);
if (nents != sgt->nents) {
sg_free_table(sgt);
ret = sg_alloc_table(sgt, nents, GFP_KERNEL);
if (ret)
return ERR_PTR(ret);
}
pbuf = buf;
for_each_sg(sgt->sgl, sg, sgt->nents, i) {
size_t bytes = min_t(size_t, len, PAGE_SIZE);
if (buf) {
sg_set_page(sg, virt_to_page(pbuf), bytes,
offset_in_page(pbuf));
} else {
sg_set_page(sg, virt_to_page(espi->zeropage),
bytes, 0);
}
pbuf += bytes;
len -= bytes;
}
if (WARN_ON(len)) {
dev_warn(&espi->pdev->dev, "len = %d expected 0!", len);
return ERR_PTR(-EINVAL);
}
nents = dma_map_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
if (!nents)
return ERR_PTR(-ENOMEM);
txd = chan->device->device_prep_slave_sg(chan, sgt->sgl, nents,
dir, DMA_CTRL_ACK);
if (!txd) {
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
return ERR_PTR(-ENOMEM);
}
return txd;
}
/**
* ep93xx_spi_dma_finish() - finishes with a DMA transfer
* @espi: ep93xx SPI controller struct
* @dir: DMA transfer direction
*
* Function finishes with the DMA transfer. After this, the DMA buffer is
* unmapped.
*/
static void ep93xx_spi_dma_finish(struct ep93xx_spi *espi,
enum dma_data_direction dir)
{
struct dma_chan *chan;
struct sg_table *sgt;
if (dir == DMA_FROM_DEVICE) {
chan = espi->dma_rx;
sgt = &espi->rx_sgt;
} else {
chan = espi->dma_tx;
sgt = &espi->tx_sgt;
}
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
}
static void ep93xx_spi_dma_callback(void *callback_param)
{
complete(callback_param);
}
static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi)
{
struct spi_message *msg = espi->current_msg;
struct dma_async_tx_descriptor *rxd, *txd;
rxd = ep93xx_spi_dma_prepare(espi, DMA_FROM_DEVICE);
if (IS_ERR(rxd)) {
dev_err(&espi->pdev->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
msg->status = PTR_ERR(rxd);
return;
}
txd = ep93xx_spi_dma_prepare(espi, DMA_TO_DEVICE);
if (IS_ERR(txd)) {
ep93xx_spi_dma_finish(espi, DMA_FROM_DEVICE);
dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(rxd));
msg->status = PTR_ERR(txd);
return;
}
/* We are ready when RX is done */
rxd->callback = ep93xx_spi_dma_callback;
rxd->callback_param = &espi->wait;
/* Now submit both descriptors and wait while they finish */
dmaengine_submit(rxd);
dmaengine_submit(txd);
dma_async_issue_pending(espi->dma_rx);
dma_async_issue_pending(espi->dma_tx);
wait_for_completion(&espi->wait);
ep93xx_spi_dma_finish(espi, DMA_TO_DEVICE);
ep93xx_spi_dma_finish(espi, DMA_FROM_DEVICE);
}
/**
* ep93xx_spi_process_transfer() - processes one SPI transfer
* @espi: ep93xx SPI controller struct
@ -556,13 +757,14 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
espi->tx = 0;
/*
* Now everything is set up for the current transfer. We prime the TX
* FIFO, enable interrupts, and wait for the transfer to complete.
* There is no point of setting up DMA for the transfers which will
* fit into the FIFO and can be transferred with a single interrupt.
* So in these cases we will be using PIO and don't bother for DMA.
*/
if (ep93xx_spi_read_write(espi)) {
ep93xx_spi_enable_interrupts(espi);
wait_for_completion(&espi->wait);
}
if (espi->dma_rx && t->len > SPI_FIFO_SIZE)
ep93xx_spi_dma_transfer(espi);
else
ep93xx_spi_pio_transfer(espi);
/*
* In case of error during transmit, we bail out from processing
@ -571,6 +773,8 @@ static void ep93xx_spi_process_transfer(struct ep93xx_spi *espi,
if (msg->status)
return;
msg->actual_length += t->len;
/*
* After this transfer is finished, perform any possible
* post-transfer actions requested by the protocol driver.
@ -752,6 +956,75 @@ static irqreturn_t ep93xx_spi_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static bool ep93xx_spi_dma_filter(struct dma_chan *chan, void *filter_param)
{
if (ep93xx_dma_chan_is_m2p(chan))
return false;
chan->private = filter_param;
return true;
}
static int ep93xx_spi_setup_dma(struct ep93xx_spi *espi)
{
dma_cap_mask_t mask;
int ret;
espi->zeropage = (void *)get_zeroed_page(GFP_KERNEL);
if (!espi->zeropage)
return -ENOMEM;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
espi->dma_rx_data.port = EP93XX_DMA_SSP;
espi->dma_rx_data.direction = DMA_FROM_DEVICE;
espi->dma_rx_data.name = "ep93xx-spi-rx";
espi->dma_rx = dma_request_channel(mask, ep93xx_spi_dma_filter,
&espi->dma_rx_data);
if (!espi->dma_rx) {
ret = -ENODEV;
goto fail_free_page;
}
espi->dma_tx_data.port = EP93XX_DMA_SSP;
espi->dma_tx_data.direction = DMA_TO_DEVICE;
espi->dma_tx_data.name = "ep93xx-spi-tx";
espi->dma_tx = dma_request_channel(mask, ep93xx_spi_dma_filter,
&espi->dma_tx_data);
if (!espi->dma_tx) {
ret = -ENODEV;
goto fail_release_rx;
}
return 0;
fail_release_rx:
dma_release_channel(espi->dma_rx);
espi->dma_rx = NULL;
fail_free_page:
free_page((unsigned long)espi->zeropage);
return ret;
}
static void ep93xx_spi_release_dma(struct ep93xx_spi *espi)
{
if (espi->dma_rx) {
dma_release_channel(espi->dma_rx);
sg_free_table(&espi->rx_sgt);
}
if (espi->dma_tx) {
dma_release_channel(espi->dma_tx);
sg_free_table(&espi->tx_sgt);
}
if (espi->zeropage)
free_page((unsigned long)espi->zeropage);
}
static int __init ep93xx_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
@ -818,6 +1091,7 @@ static int __init ep93xx_spi_probe(struct platform_device *pdev)
goto fail_put_clock;
}
espi->sspdr_phys = res->start + SSPDR;
espi->regs_base = ioremap(res->start, resource_size(res));
if (!espi->regs_base) {
dev_err(&pdev->dev, "failed to map resources\n");
@ -832,10 +1106,13 @@ static int __init ep93xx_spi_probe(struct platform_device *pdev)
goto fail_unmap_regs;
}
if (info->use_dma && ep93xx_spi_setup_dma(espi))
dev_warn(&pdev->dev, "DMA setup failed. Falling back to PIO\n");
espi->wq = create_singlethread_workqueue("ep93xx_spid");
if (!espi->wq) {
dev_err(&pdev->dev, "unable to create workqueue\n");
goto fail_free_irq;
goto fail_free_dma;
}
INIT_WORK(&espi->msg_work, ep93xx_spi_work);
INIT_LIST_HEAD(&espi->msg_queue);
@ -857,7 +1134,8 @@ static int __init ep93xx_spi_probe(struct platform_device *pdev)
fail_free_queue:
destroy_workqueue(espi->wq);
fail_free_irq:
fail_free_dma:
ep93xx_spi_release_dma(espi);
free_irq(espi->irq, espi);
fail_unmap_regs:
iounmap(espi->regs_base);
@ -901,6 +1179,7 @@ static int __exit ep93xx_spi_remove(struct platform_device *pdev)
}
spin_unlock_irq(&espi->lock);
ep93xx_spi_release_dma(espi);
free_irq(espi->irq, espi);
iounmap(espi->regs_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

View File

@ -22,7 +22,7 @@
#include <linux/err.h>
#include <sysdev/fsl_soc.h>
#include "spi_fsl_lib.h"
#include "spi-fsl-lib.h"
/* eSPI Controller registers */
struct fsl_espi_reg {

View File

@ -25,7 +25,7 @@
#include <linux/of_spi.h>
#include <sysdev/fsl_soc.h>
#include "spi_fsl_lib.h"
#include "spi-fsl-lib.h"
#define MPC8XXX_SPI_RX_BUF(type) \
void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \

View File

@ -37,7 +37,7 @@
#include <asm/cpm.h>
#include <asm/qe.h>
#include "spi_fsl_lib.h"
#include "spi-fsl-lib.h"
/* CPM1 and CPM2 are mutually exclusive. */
#ifdef CONFIG_CPM1
@ -684,7 +684,7 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
struct device_node *np = dev->of_node;
const u32 *iprop;
int size;
unsigned long spi_base_ofs;
void __iomem *spi_base;
unsigned long pram_ofs = -ENOMEM;
/* Can't use of_address_to_resource(), QE muram isn't at 0. */
@ -702,33 +702,27 @@ static unsigned long fsl_spi_cpm_get_pram(struct mpc8xxx_spi *mspi)
return pram_ofs;
}
/* CPM1 and CPM2 pram must be at a fixed addr. */
if (!iprop || size != sizeof(*iprop) * 4)
return -ENOMEM;
spi_base_ofs = cpm_muram_alloc_fixed(iprop[2], 2);
if (IS_ERR_VALUE(spi_base_ofs))
return -ENOMEM;
spi_base = of_iomap(np, 1);
if (spi_base == NULL)
return -EINVAL;
if (mspi->flags & SPI_CPM2) {
pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
if (!IS_ERR_VALUE(pram_ofs)) {
u16 __iomem *spi_base = cpm_muram_addr(spi_base_ofs);
out_be16(spi_base, pram_ofs);
}
out_be16(spi_base, pram_ofs);
} else {
struct spi_pram __iomem *pram = cpm_muram_addr(spi_base_ofs);
struct spi_pram __iomem *pram = spi_base;
u16 rpbase = in_be16(&pram->rpbase);
/* Microcode relocation patch applied? */
if (rpbase)
pram_ofs = rpbase;
else
return spi_base_ofs;
else {
pram_ofs = cpm_muram_alloc(SPI_PRAM_SIZE, 64);
out_be16(spi_base, pram_ofs);
}
}
cpm_muram_free(spi_base_ofs);
iounmap(spi_base);
return pram_ofs;
}

View File

@ -1,5 +1,5 @@
/*
* spi_gpio.c - SPI master driver using generic bitbanged GPIO
* SPI master driver using generic bitbanged GPIO
*
* Copyright (C) 2006,2008 David Brownell
*
@ -69,7 +69,7 @@ struct spi_gpio {
* #define SPI_MOSI_GPIO 120
* #define SPI_SCK_GPIO 121
* #define SPI_N_CHIPSEL 4
* #include "spi_gpio.c"
* #include "spi-gpio.c"
*/
#ifndef DRIVER_NAME
@ -127,7 +127,7 @@ static inline int getmiso(const struct spi_device *spi)
*/
#define spidelay(nsecs) do {} while (0)
#include "spi_bitbang_txrx.h"
#include "spi-bitbang-txrx.h"
/*
* These functions can leverage inline expansion of GPIO calls to shrink

View File

@ -34,6 +34,9 @@
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <linux/types.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <mach/spi.h>
@ -45,9 +48,6 @@
#define MXC_CSPIINT 0x0c
#define MXC_RESET 0x1c
#define MX3_CSPISTAT 0x14
#define MX3_CSPISTAT_RR (1 << 3)
/* generic defines to abstract from the different register layouts */
#define MXC_INT_RR (1 << 0) /* Receive data ready interrupt */
#define MXC_INT_TE (1 << 1) /* Transmit FIFO empty interrupt */
@ -60,12 +60,12 @@ struct spi_imx_config {
};
enum spi_imx_devtype {
SPI_IMX_VER_IMX1,
SPI_IMX_VER_0_0,
SPI_IMX_VER_0_4,
SPI_IMX_VER_0_5,
SPI_IMX_VER_0_7,
SPI_IMX_VER_2_3,
IMX1_CSPI,
IMX21_CSPI,
IMX27_CSPI,
IMX31_CSPI,
IMX35_CSPI, /* CSPI on all i.mx except above */
IMX51_ECSPI, /* ECSPI on i.mx51 and later */
};
struct spi_imx_data;
@ -76,7 +76,7 @@ struct spi_imx_devtype_data {
void (*trigger)(struct spi_imx_data *);
int (*rx_available)(struct spi_imx_data *);
void (*reset)(struct spi_imx_data *);
unsigned int fifosize;
enum spi_imx_devtype devtype;
};
struct spi_imx_data {
@ -87,7 +87,6 @@ struct spi_imx_data {
int irq;
struct clk *clk;
unsigned long spi_clk;
int *chipselect;
unsigned int count;
void (*tx)(struct spi_imx_data *);
@ -96,9 +95,25 @@ struct spi_imx_data {
const void *tx_buf;
unsigned int txfifo; /* number of words pushed in tx FIFO */
struct spi_imx_devtype_data devtype_data;
struct spi_imx_devtype_data *devtype_data;
int chipselect[0];
};
static inline int is_imx27_cspi(struct spi_imx_data *d)
{
return d->devtype_data->devtype == IMX27_CSPI;
}
static inline int is_imx35_cspi(struct spi_imx_data *d)
{
return d->devtype_data->devtype == IMX35_CSPI;
}
static inline unsigned spi_imx_get_fifosize(struct spi_imx_data *d)
{
return (d->devtype_data->devtype == IMX51_ECSPI) ? 64 : 8;
}
#define MXC_SPI_BUF_RX(type) \
static void spi_imx_buf_rx_##type(struct spi_imx_data *spi_imx) \
{ \
@ -140,14 +155,9 @@ static int mxc_clkdivs[] = {0, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192,
/* MX21, MX27 */
static unsigned int spi_imx_clkdiv_1(unsigned int fin,
unsigned int fspi)
unsigned int fspi, unsigned int max)
{
int i, max;
if (cpu_is_mx21())
max = 18;
else
max = 16;
int i;
for (i = 2; i < max; i++)
if (fspi * mxc_clkdivs[i] >= fin)
@ -171,30 +181,30 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
return 7;
}
#define SPI_IMX2_3_CTRL 0x08
#define SPI_IMX2_3_CTRL_ENABLE (1 << 0)
#define SPI_IMX2_3_CTRL_XCH (1 << 2)
#define SPI_IMX2_3_CTRL_MODE_MASK (0xf << 4)
#define SPI_IMX2_3_CTRL_POSTDIV_OFFSET 8
#define SPI_IMX2_3_CTRL_PREDIV_OFFSET 12
#define SPI_IMX2_3_CTRL_CS(cs) ((cs) << 18)
#define SPI_IMX2_3_CTRL_BL_OFFSET 20
#define MX51_ECSPI_CTRL 0x08
#define MX51_ECSPI_CTRL_ENABLE (1 << 0)
#define MX51_ECSPI_CTRL_XCH (1 << 2)
#define MX51_ECSPI_CTRL_MODE_MASK (0xf << 4)
#define MX51_ECSPI_CTRL_POSTDIV_OFFSET 8
#define MX51_ECSPI_CTRL_PREDIV_OFFSET 12
#define MX51_ECSPI_CTRL_CS(cs) ((cs) << 18)
#define MX51_ECSPI_CTRL_BL_OFFSET 20
#define SPI_IMX2_3_CONFIG 0x0c
#define SPI_IMX2_3_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0))
#define SPI_IMX2_3_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4))
#define SPI_IMX2_3_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8))
#define SPI_IMX2_3_CONFIG_SSBPOL(cs) (1 << ((cs) + 12))
#define MX51_ECSPI_CONFIG 0x0c
#define MX51_ECSPI_CONFIG_SCLKPHA(cs) (1 << ((cs) + 0))
#define MX51_ECSPI_CONFIG_SCLKPOL(cs) (1 << ((cs) + 4))
#define MX51_ECSPI_CONFIG_SBBCTRL(cs) (1 << ((cs) + 8))
#define MX51_ECSPI_CONFIG_SSBPOL(cs) (1 << ((cs) + 12))
#define SPI_IMX2_3_INT 0x10
#define SPI_IMX2_3_INT_TEEN (1 << 0)
#define SPI_IMX2_3_INT_RREN (1 << 3)
#define MX51_ECSPI_INT 0x10
#define MX51_ECSPI_INT_TEEN (1 << 0)
#define MX51_ECSPI_INT_RREN (1 << 3)
#define SPI_IMX2_3_STAT 0x18
#define SPI_IMX2_3_STAT_RR (1 << 3)
#define MX51_ECSPI_STAT 0x18
#define MX51_ECSPI_STAT_RR (1 << 3)
/* MX51 eCSPI */
static unsigned int spi_imx2_3_clkdiv(unsigned int fin, unsigned int fspi)
static unsigned int mx51_ecspi_clkdiv(unsigned int fin, unsigned int fspi)
{
/*
* there are two 4-bit dividers, the pre-divider divides by
@ -222,36 +232,36 @@ static unsigned int spi_imx2_3_clkdiv(unsigned int fin, unsigned int fspi)
pr_debug("%s: fin: %u, fspi: %u, post: %u, pre: %u\n",
__func__, fin, fspi, post, pre);
return (pre << SPI_IMX2_3_CTRL_PREDIV_OFFSET) |
(post << SPI_IMX2_3_CTRL_POSTDIV_OFFSET);
return (pre << MX51_ECSPI_CTRL_PREDIV_OFFSET) |
(post << MX51_ECSPI_CTRL_POSTDIV_OFFSET);
}
static void __maybe_unused spi_imx2_3_intctrl(struct spi_imx_data *spi_imx, int enable)
static void __maybe_unused mx51_ecspi_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned val = 0;
if (enable & MXC_INT_TE)
val |= SPI_IMX2_3_INT_TEEN;
val |= MX51_ECSPI_INT_TEEN;
if (enable & MXC_INT_RR)
val |= SPI_IMX2_3_INT_RREN;
val |= MX51_ECSPI_INT_RREN;
writel(val, spi_imx->base + SPI_IMX2_3_INT);
writel(val, spi_imx->base + MX51_ECSPI_INT);
}
static void __maybe_unused spi_imx2_3_trigger(struct spi_imx_data *spi_imx)
static void __maybe_unused mx51_ecspi_trigger(struct spi_imx_data *spi_imx)
{
u32 reg;
reg = readl(spi_imx->base + SPI_IMX2_3_CTRL);
reg |= SPI_IMX2_3_CTRL_XCH;
writel(reg, spi_imx->base + SPI_IMX2_3_CTRL);
reg = readl(spi_imx->base + MX51_ECSPI_CTRL);
reg |= MX51_ECSPI_CTRL_XCH;
writel(reg, spi_imx->base + MX51_ECSPI_CTRL);
}
static int __maybe_unused spi_imx2_3_config(struct spi_imx_data *spi_imx,
static int __maybe_unused mx51_ecspi_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
u32 ctrl = SPI_IMX2_3_CTRL_ENABLE, cfg = 0;
u32 ctrl = MX51_ECSPI_CTRL_ENABLE, cfg = 0;
/*
* The hardware seems to have a race condition when changing modes. The
@ -260,42 +270,42 @@ static int __maybe_unused spi_imx2_3_config(struct spi_imx_data *spi_imx,
* the same time.
* So set master mode for all channels as we do not support slave mode.
*/
ctrl |= SPI_IMX2_3_CTRL_MODE_MASK;
ctrl |= MX51_ECSPI_CTRL_MODE_MASK;
/* set clock speed */
ctrl |= spi_imx2_3_clkdiv(spi_imx->spi_clk, config->speed_hz);
ctrl |= mx51_ecspi_clkdiv(spi_imx->spi_clk, config->speed_hz);
/* set chip select to use */
ctrl |= SPI_IMX2_3_CTRL_CS(config->cs);
ctrl |= MX51_ECSPI_CTRL_CS(config->cs);
ctrl |= (config->bpw - 1) << SPI_IMX2_3_CTRL_BL_OFFSET;
ctrl |= (config->bpw - 1) << MX51_ECSPI_CTRL_BL_OFFSET;
cfg |= SPI_IMX2_3_CONFIG_SBBCTRL(config->cs);
cfg |= MX51_ECSPI_CONFIG_SBBCTRL(config->cs);
if (config->mode & SPI_CPHA)
cfg |= SPI_IMX2_3_CONFIG_SCLKPHA(config->cs);
cfg |= MX51_ECSPI_CONFIG_SCLKPHA(config->cs);
if (config->mode & SPI_CPOL)
cfg |= SPI_IMX2_3_CONFIG_SCLKPOL(config->cs);
cfg |= MX51_ECSPI_CONFIG_SCLKPOL(config->cs);
if (config->mode & SPI_CS_HIGH)
cfg |= SPI_IMX2_3_CONFIG_SSBPOL(config->cs);
cfg |= MX51_ECSPI_CONFIG_SSBPOL(config->cs);
writel(ctrl, spi_imx->base + SPI_IMX2_3_CTRL);
writel(cfg, spi_imx->base + SPI_IMX2_3_CONFIG);
writel(ctrl, spi_imx->base + MX51_ECSPI_CTRL);
writel(cfg, spi_imx->base + MX51_ECSPI_CONFIG);
return 0;
}
static int __maybe_unused spi_imx2_3_rx_available(struct spi_imx_data *spi_imx)
static int __maybe_unused mx51_ecspi_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + SPI_IMX2_3_STAT) & SPI_IMX2_3_STAT_RR;
return readl(spi_imx->base + MX51_ECSPI_STAT) & MX51_ECSPI_STAT_RR;
}
static void __maybe_unused spi_imx2_3_reset(struct spi_imx_data *spi_imx)
static void __maybe_unused mx51_ecspi_reset(struct spi_imx_data *spi_imx)
{
/* drain receive buffer */
while (spi_imx2_3_rx_available(spi_imx))
while (mx51_ecspi_rx_available(spi_imx))
readl(spi_imx->base + MXC_CSPIRXDATA);
}
@ -343,7 +353,7 @@ static void __maybe_unused mx31_trigger(struct spi_imx_data *spi_imx)
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
static int __maybe_unused spi_imx0_4_config(struct spi_imx_data *spi_imx,
static int __maybe_unused mx31_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
@ -352,7 +362,12 @@ static int __maybe_unused spi_imx0_4_config(struct spi_imx_data *spi_imx,
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
MX31_CSPICTRL_DR_SHIFT;
reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
if (is_imx35_cspi(spi_imx)) {
reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
reg |= MX31_CSPICTRL_SSCTL;
} else {
reg |= (config->bpw - 1) << MX31_CSPICTRL_BC_SHIFT;
}
if (config->mode & SPI_CPHA)
reg |= MX31_CSPICTRL_PHA;
@ -361,33 +376,9 @@ static int __maybe_unused spi_imx0_4_config(struct spi_imx_data *spi_imx,
if (config->mode & SPI_CS_HIGH)
reg |= MX31_CSPICTRL_SSPOL;
if (cs < 0)
reg |= (cs + 32) << MX31_CSPICTRL_CS_SHIFT;
writel(reg, spi_imx->base + MXC_CSPICTRL);
return 0;
}
static int __maybe_unused spi_imx0_7_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
unsigned int reg = MX31_CSPICTRL_ENABLE | MX31_CSPICTRL_MASTER;
int cs = spi_imx->chipselect[config->cs];
reg |= spi_imx_clkdiv_2(spi_imx->spi_clk, config->speed_hz) <<
MX31_CSPICTRL_DR_SHIFT;
reg |= (config->bpw - 1) << MX35_CSPICTRL_BL_SHIFT;
reg |= MX31_CSPICTRL_SSCTL;
if (config->mode & SPI_CPHA)
reg |= MX31_CSPICTRL_PHA;
if (config->mode & SPI_CPOL)
reg |= MX31_CSPICTRL_POL;
if (config->mode & SPI_CS_HIGH)
reg |= MX31_CSPICTRL_SSPOL;
if (cs < 0)
reg |= (cs + 32) << MX35_CSPICTRL_CS_SHIFT;
reg |= (cs + 32) <<
(is_imx35_cspi(spi_imx) ? MX35_CSPICTRL_CS_SHIFT :
MX31_CSPICTRL_CS_SHIFT);
writel(reg, spi_imx->base + MXC_CSPICTRL);
@ -399,77 +390,78 @@ static int __maybe_unused mx31_rx_available(struct spi_imx_data *spi_imx)
return readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR;
}
static void __maybe_unused spi_imx0_4_reset(struct spi_imx_data *spi_imx)
static void __maybe_unused mx31_reset(struct spi_imx_data *spi_imx)
{
/* drain receive buffer */
while (readl(spi_imx->base + MX3_CSPISTAT) & MX3_CSPISTAT_RR)
while (readl(spi_imx->base + MX31_CSPISTATUS) & MX31_STATUS_RR)
readl(spi_imx->base + MXC_CSPIRXDATA);
}
#define MX27_INTREG_RR (1 << 4)
#define MX27_INTREG_TEEN (1 << 9)
#define MX27_INTREG_RREN (1 << 13)
#define MX21_INTREG_RR (1 << 4)
#define MX21_INTREG_TEEN (1 << 9)
#define MX21_INTREG_RREN (1 << 13)
#define MX27_CSPICTRL_POL (1 << 5)
#define MX27_CSPICTRL_PHA (1 << 6)
#define MX27_CSPICTRL_SSPOL (1 << 8)
#define MX27_CSPICTRL_XCH (1 << 9)
#define MX27_CSPICTRL_ENABLE (1 << 10)
#define MX27_CSPICTRL_MASTER (1 << 11)
#define MX27_CSPICTRL_DR_SHIFT 14
#define MX27_CSPICTRL_CS_SHIFT 19
#define MX21_CSPICTRL_POL (1 << 5)
#define MX21_CSPICTRL_PHA (1 << 6)
#define MX21_CSPICTRL_SSPOL (1 << 8)
#define MX21_CSPICTRL_XCH (1 << 9)
#define MX21_CSPICTRL_ENABLE (1 << 10)
#define MX21_CSPICTRL_MASTER (1 << 11)
#define MX21_CSPICTRL_DR_SHIFT 14
#define MX21_CSPICTRL_CS_SHIFT 19
static void __maybe_unused mx27_intctrl(struct spi_imx_data *spi_imx, int enable)
static void __maybe_unused mx21_intctrl(struct spi_imx_data *spi_imx, int enable)
{
unsigned int val = 0;
if (enable & MXC_INT_TE)
val |= MX27_INTREG_TEEN;
val |= MX21_INTREG_TEEN;
if (enable & MXC_INT_RR)
val |= MX27_INTREG_RREN;
val |= MX21_INTREG_RREN;
writel(val, spi_imx->base + MXC_CSPIINT);
}
static void __maybe_unused mx27_trigger(struct spi_imx_data *spi_imx)
static void __maybe_unused mx21_trigger(struct spi_imx_data *spi_imx)
{
unsigned int reg;
reg = readl(spi_imx->base + MXC_CSPICTRL);
reg |= MX27_CSPICTRL_XCH;
reg |= MX21_CSPICTRL_XCH;
writel(reg, spi_imx->base + MXC_CSPICTRL);
}
static int __maybe_unused mx27_config(struct spi_imx_data *spi_imx,
static int __maybe_unused mx21_config(struct spi_imx_data *spi_imx,
struct spi_imx_config *config)
{
unsigned int reg = MX27_CSPICTRL_ENABLE | MX27_CSPICTRL_MASTER;
unsigned int reg = MX21_CSPICTRL_ENABLE | MX21_CSPICTRL_MASTER;
int cs = spi_imx->chipselect[config->cs];
unsigned int max = is_imx27_cspi(spi_imx) ? 16 : 18;
reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz) <<
MX27_CSPICTRL_DR_SHIFT;
reg |= spi_imx_clkdiv_1(spi_imx->spi_clk, config->speed_hz, max) <<
MX21_CSPICTRL_DR_SHIFT;
reg |= config->bpw - 1;
if (config->mode & SPI_CPHA)
reg |= MX27_CSPICTRL_PHA;
reg |= MX21_CSPICTRL_PHA;
if (config->mode & SPI_CPOL)
reg |= MX27_CSPICTRL_POL;
reg |= MX21_CSPICTRL_POL;
if (config->mode & SPI_CS_HIGH)
reg |= MX27_CSPICTRL_SSPOL;
reg |= MX21_CSPICTRL_SSPOL;
if (cs < 0)
reg |= (cs + 32) << MX27_CSPICTRL_CS_SHIFT;
reg |= (cs + 32) << MX21_CSPICTRL_CS_SHIFT;
writel(reg, spi_imx->base + MXC_CSPICTRL);
return 0;
}
static int __maybe_unused mx27_rx_available(struct spi_imx_data *spi_imx)
static int __maybe_unused mx21_rx_available(struct spi_imx_data *spi_imx)
{
return readl(spi_imx->base + MXC_CSPIINT) & MX27_INTREG_RR;
return readl(spi_imx->base + MXC_CSPIINT) & MX21_INTREG_RR;
}
static void __maybe_unused spi_imx0_0_reset(struct spi_imx_data *spi_imx)
static void __maybe_unused mx21_reset(struct spi_imx_data *spi_imx)
{
writel(1, spi_imx->base + MXC_RESET);
}
@ -535,61 +527,94 @@ static void __maybe_unused mx1_reset(struct spi_imx_data *spi_imx)
writel(1, spi_imx->base + MXC_RESET);
}
/*
* These version numbers are taken from the Freescale driver. Unfortunately it
* doesn't support i.MX1, so this entry doesn't match the scheme. :-(
*/
static struct spi_imx_devtype_data spi_imx_devtype_data[] __devinitdata = {
#ifdef CONFIG_SPI_IMX_VER_IMX1
[SPI_IMX_VER_IMX1] = {
.intctrl = mx1_intctrl,
.config = mx1_config,
.trigger = mx1_trigger,
.rx_available = mx1_rx_available,
.reset = mx1_reset,
.fifosize = 8,
},
#endif
#ifdef CONFIG_SPI_IMX_VER_0_0
[SPI_IMX_VER_0_0] = {
.intctrl = mx27_intctrl,
.config = mx27_config,
.trigger = mx27_trigger,
.rx_available = mx27_rx_available,
.reset = spi_imx0_0_reset,
.fifosize = 8,
},
#endif
#ifdef CONFIG_SPI_IMX_VER_0_4
[SPI_IMX_VER_0_4] = {
.intctrl = mx31_intctrl,
.config = spi_imx0_4_config,
.trigger = mx31_trigger,
.rx_available = mx31_rx_available,
.reset = spi_imx0_4_reset,
.fifosize = 8,
},
#endif
#ifdef CONFIG_SPI_IMX_VER_0_7
[SPI_IMX_VER_0_7] = {
.intctrl = mx31_intctrl,
.config = spi_imx0_7_config,
.trigger = mx31_trigger,
.rx_available = mx31_rx_available,
.reset = spi_imx0_4_reset,
.fifosize = 8,
},
#endif
#ifdef CONFIG_SPI_IMX_VER_2_3
[SPI_IMX_VER_2_3] = {
.intctrl = spi_imx2_3_intctrl,
.config = spi_imx2_3_config,
.trigger = spi_imx2_3_trigger,
.rx_available = spi_imx2_3_rx_available,
.reset = spi_imx2_3_reset,
.fifosize = 64,
},
#endif
static struct spi_imx_devtype_data imx1_cspi_devtype_data = {
.intctrl = mx1_intctrl,
.config = mx1_config,
.trigger = mx1_trigger,
.rx_available = mx1_rx_available,
.reset = mx1_reset,
.devtype = IMX1_CSPI,
};
static struct spi_imx_devtype_data imx21_cspi_devtype_data = {
.intctrl = mx21_intctrl,
.config = mx21_config,
.trigger = mx21_trigger,
.rx_available = mx21_rx_available,
.reset = mx21_reset,
.devtype = IMX21_CSPI,
};
static struct spi_imx_devtype_data imx27_cspi_devtype_data = {
/* i.mx27 cspi shares the functions with i.mx21 one */
.intctrl = mx21_intctrl,
.config = mx21_config,
.trigger = mx21_trigger,
.rx_available = mx21_rx_available,
.reset = mx21_reset,
.devtype = IMX27_CSPI,
};
static struct spi_imx_devtype_data imx31_cspi_devtype_data = {
.intctrl = mx31_intctrl,
.config = mx31_config,
.trigger = mx31_trigger,
.rx_available = mx31_rx_available,
.reset = mx31_reset,
.devtype = IMX31_CSPI,
};
static struct spi_imx_devtype_data imx35_cspi_devtype_data = {
/* i.mx35 and later cspi shares the functions with i.mx31 one */
.intctrl = mx31_intctrl,
.config = mx31_config,
.trigger = mx31_trigger,
.rx_available = mx31_rx_available,
.reset = mx31_reset,
.devtype = IMX35_CSPI,
};
static struct spi_imx_devtype_data imx51_ecspi_devtype_data = {
.intctrl = mx51_ecspi_intctrl,
.config = mx51_ecspi_config,
.trigger = mx51_ecspi_trigger,
.rx_available = mx51_ecspi_rx_available,
.reset = mx51_ecspi_reset,
.devtype = IMX51_ECSPI,
};
static struct platform_device_id spi_imx_devtype[] = {
{
.name = "imx1-cspi",
.driver_data = (kernel_ulong_t) &imx1_cspi_devtype_data,
}, {
.name = "imx21-cspi",
.driver_data = (kernel_ulong_t) &imx21_cspi_devtype_data,
}, {
.name = "imx27-cspi",
.driver_data = (kernel_ulong_t) &imx27_cspi_devtype_data,
}, {
.name = "imx31-cspi",
.driver_data = (kernel_ulong_t) &imx31_cspi_devtype_data,
}, {
.name = "imx35-cspi",
.driver_data = (kernel_ulong_t) &imx35_cspi_devtype_data,
}, {
.name = "imx51-ecspi",
.driver_data = (kernel_ulong_t) &imx51_ecspi_devtype_data,
}, {
/* sentinel */
}
};
static const struct of_device_id spi_imx_dt_ids[] = {
{ .compatible = "fsl,imx1-cspi", .data = &imx1_cspi_devtype_data, },
{ .compatible = "fsl,imx21-cspi", .data = &imx21_cspi_devtype_data, },
{ .compatible = "fsl,imx27-cspi", .data = &imx27_cspi_devtype_data, },
{ .compatible = "fsl,imx31-cspi", .data = &imx31_cspi_devtype_data, },
{ .compatible = "fsl,imx35-cspi", .data = &imx35_cspi_devtype_data, },
{ .compatible = "fsl,imx51-ecspi", .data = &imx51_ecspi_devtype_data, },
{ /* sentinel */ }
};
static void spi_imx_chipselect(struct spi_device *spi, int is_active)
@ -607,21 +632,21 @@ static void spi_imx_chipselect(struct spi_device *spi, int is_active)
static void spi_imx_push(struct spi_imx_data *spi_imx)
{
while (spi_imx->txfifo < spi_imx->devtype_data.fifosize) {
while (spi_imx->txfifo < spi_imx_get_fifosize(spi_imx)) {
if (!spi_imx->count)
break;
spi_imx->tx(spi_imx);
spi_imx->txfifo++;
}
spi_imx->devtype_data.trigger(spi_imx);
spi_imx->devtype_data->trigger(spi_imx);
}
static irqreturn_t spi_imx_isr(int irq, void *dev_id)
{
struct spi_imx_data *spi_imx = dev_id;
while (spi_imx->devtype_data.rx_available(spi_imx)) {
while (spi_imx->devtype_data->rx_available(spi_imx)) {
spi_imx->rx(spi_imx);
spi_imx->txfifo--;
}
@ -635,12 +660,12 @@ static irqreturn_t spi_imx_isr(int irq, void *dev_id)
/* No data left to push, but still waiting for rx data,
* enable receive data available interrupt.
*/
spi_imx->devtype_data.intctrl(
spi_imx->devtype_data->intctrl(
spi_imx, MXC_INT_RR);
return IRQ_HANDLED;
}
spi_imx->devtype_data.intctrl(spi_imx, 0);
spi_imx->devtype_data->intctrl(spi_imx, 0);
complete(&spi_imx->xfer_done);
return IRQ_HANDLED;
@ -677,7 +702,7 @@ static int spi_imx_setupxfer(struct spi_device *spi,
} else
BUG();
spi_imx->devtype_data.config(spi_imx, &config);
spi_imx->devtype_data->config(spi_imx, &config);
return 0;
}
@ -696,7 +721,7 @@ static int spi_imx_transfer(struct spi_device *spi,
spi_imx_push(spi_imx);
spi_imx->devtype_data.intctrl(spi_imx, MXC_INT_TE);
spi_imx->devtype_data->intctrl(spi_imx, MXC_INT_TE);
wait_for_completion(&spi_imx->xfer_done);
@ -723,72 +748,47 @@ static void spi_imx_cleanup(struct spi_device *spi)
{
}
static struct platform_device_id spi_imx_devtype[] = {
{
.name = "imx1-cspi",
.driver_data = SPI_IMX_VER_IMX1,
}, {
.name = "imx21-cspi",
.driver_data = SPI_IMX_VER_0_0,
}, {
.name = "imx25-cspi",
.driver_data = SPI_IMX_VER_0_7,
}, {
.name = "imx27-cspi",
.driver_data = SPI_IMX_VER_0_0,
}, {
.name = "imx31-cspi",
.driver_data = SPI_IMX_VER_0_4,
}, {
.name = "imx35-cspi",
.driver_data = SPI_IMX_VER_0_7,
}, {
.name = "imx51-cspi",
.driver_data = SPI_IMX_VER_0_7,
}, {
.name = "imx51-ecspi",
.driver_data = SPI_IMX_VER_2_3,
}, {
.name = "imx53-cspi",
.driver_data = SPI_IMX_VER_0_7,
}, {
.name = "imx53-ecspi",
.driver_data = SPI_IMX_VER_2_3,
}, {
/* sentinel */
}
};
static int __devinit spi_imx_probe(struct platform_device *pdev)
{
struct spi_imx_master *mxc_platform_info;
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *of_id =
of_match_device(spi_imx_dt_ids, &pdev->dev);
struct spi_imx_master *mxc_platform_info =
dev_get_platdata(&pdev->dev);
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
int i, ret;
int i, ret, num_cs;
mxc_platform_info = dev_get_platdata(&pdev->dev);
if (!mxc_platform_info) {
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
return -EINVAL;
}
master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
ret = of_property_read_u32(np, "fsl,spi-num-chipselects", &num_cs);
if (ret < 0)
num_cs = mxc_platform_info->num_chipselect;
master = spi_alloc_master(&pdev->dev,
sizeof(struct spi_imx_data) + sizeof(int) * num_cs);
if (!master)
return -ENOMEM;
platform_set_drvdata(pdev, master);
master->bus_num = pdev->id;
master->num_chipselect = mxc_platform_info->num_chipselect;
master->num_chipselect = num_cs;
spi_imx = spi_master_get_devdata(master);
spi_imx->bitbang.master = spi_master_get(master);
spi_imx->chipselect = mxc_platform_info->chipselect;
for (i = 0; i < master->num_chipselect; i++) {
if (spi_imx->chipselect[i] < 0)
int cs_gpio = of_get_named_gpio(np, "cs-gpios", i);
if (cs_gpio < 0)
cs_gpio = mxc_platform_info->chipselect[i];
if (cs_gpio < 0)
continue;
spi_imx->chipselect[i] = cs_gpio;
ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);
if (ret) {
while (i > 0) {
@ -810,8 +810,8 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
init_completion(&spi_imx->xfer_done);
spi_imx->devtype_data =
spi_imx_devtype_data[pdev->id_entry->driver_data];
spi_imx->devtype_data = of_id ? of_id->data :
(struct spi_imx_devtype_data *) pdev->id_entry->driver_data;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@ -854,10 +854,11 @@ static int __devinit spi_imx_probe(struct platform_device *pdev)
clk_enable(spi_imx->clk);
spi_imx->spi_clk = clk_get_rate(spi_imx->clk);
spi_imx->devtype_data.reset(spi_imx);
spi_imx->devtype_data->reset(spi_imx);
spi_imx->devtype_data.intctrl(spi_imx, 0);
spi_imx->devtype_data->intctrl(spi_imx, 0);
master->dev.of_node = pdev->dev.of_node;
ret = spi_bitbang_start(&spi_imx->bitbang);
if (ret) {
dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);
@ -920,6 +921,7 @@ static struct platform_driver spi_imx_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = spi_imx_dt_ids,
},
.id_table = spi_imx_devtype,
.probe = spi_imx_probe,

View File

@ -1,5 +1,5 @@
/*
* spi_lm70llp.c - driver for LM70EVAL-LLP board for the LM70 sensor
* Driver for LM70EVAL-LLP board for the LM70 sensor
*
* Copyright (C) 2006 Kaiwan N Billimoria <kaiwan@designergraphix.com>
*
@ -174,7 +174,7 @@ static inline int getmiso(struct spi_device *s)
}
/*--------------------------------------------------------------------*/
#include "spi_bitbang_txrx.h"
#include "spi-bitbang-txrx.h"
static void lm70_chipselect(struct spi_device *spi, int value)
{

View File

@ -1,5 +1,4 @@
/* linux/drivers/spi/spi_nuc900.c
*
/*
* Copyright (c) 2009 Nuvoton technology.
* Wan ZongShun <mcuos.com@gmail.com>
*
@ -7,7 +6,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
*/
#include <linux/init.h>
#include <linux/spinlock.h>

View File

@ -1,5 +1,5 @@
/*
* omap_uwire.c -- MicroWire interface driver for OMAP
* MicroWire interface driver for OMAP
*
* Copyright 2003 MontaVista Software Inc. <source@mvista.com>
*

View File

@ -1116,8 +1116,8 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
status = -ENODEV;
goto err1;
}
if (!request_mem_region(r->start, (r->end - r->start) + 1,
dev_name(&pdev->dev))) {
if (!request_mem_region(r->start, resource_size(r),
dev_name(&pdev->dev))) {
status = -EBUSY;
goto err1;
}
@ -1125,7 +1125,7 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev)
r->start += pdata->regs_offset;
r->end += pdata->regs_offset;
mcspi->phys = r->start;
mcspi->base = ioremap(r->start, r->end - r->start + 1);
mcspi->base = ioremap(r->start, resource_size(r));
if (!mcspi->base) {
dev_dbg(&pdev->dev, "can't ioremap MCSPI\n");
status = -ENOMEM;
@ -1190,7 +1190,7 @@ err4:
err3:
kfree(mcspi->dma_channels);
err2:
release_mem_region(r->start, (r->end - r->start) + 1);
release_mem_region(r->start, resource_size(r));
iounmap(mcspi->base);
err1:
return status;
@ -1210,7 +1210,7 @@ static int __exit omap2_mcspi_remove(struct platform_device *pdev)
omap2_mcspi_disable_clocks(mcspi);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, (r->end - r->start) + 1);
release_mem_region(r->start, resource_size(r));
base = mcspi->base;
spi_unregister_master(master);

View File

@ -1,5 +1,5 @@
/*
* orion_spi.c -- Marvell Orion SPI controller driver
* Marvell Orion SPI controller driver
*
* Author: Shadi Ammouri <shadi@marvell.com>
* Copyright (C) 2007-2008 Marvell Ltd.
@ -489,7 +489,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
goto out;
}
if (!request_mem_region(r->start, (r->end - r->start) + 1,
if (!request_mem_region(r->start, resource_size(r),
dev_name(&pdev->dev))) {
status = -EBUSY;
goto out;
@ -511,7 +511,7 @@ static int __init orion_spi_probe(struct platform_device *pdev)
return status;
out_rel_mem:
release_mem_region(r->start, (r->end - r->start) + 1);
release_mem_region(r->start, resource_size(r));
out:
spi_master_put(master);
@ -531,7 +531,7 @@ static int __exit orion_spi_remove(struct platform_device *pdev)
cancel_work_sync(&spi->work);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, (r->end - r->start) + 1);
release_mem_region(r->start, resource_size(r));
spi_unregister_master(master);

View File

@ -1,6 +1,4 @@
/*
* drivers/spi/amba-pl022.c
*
* A driver for the ARM PL022 PrimeCell SSP/SPI bus master.
*
* Copyright (C) 2008-2009 ST-Ericsson AB
@ -42,6 +40,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <linux/scatterlist.h>
#include <linux/pm_runtime.h>
/*
* This macro is used to define some register default values.
@ -383,6 +382,8 @@ struct pl022 {
enum ssp_reading read;
enum ssp_writing write;
u32 exp_fifo_level;
enum ssp_rx_level_trig rx_lev_trig;
enum ssp_tx_level_trig tx_lev_trig;
/* DMA settings */
#ifdef CONFIG_DMA_ENGINE
struct dma_chan *dma_rx_channel;
@ -517,6 +518,7 @@ static void giveback(struct pl022 *pl022)
clk_disable(pl022->clk);
amba_pclk_disable(pl022->adev);
amba_vcore_disable(pl022->adev);
pm_runtime_put(&pl022->adev->dev);
}
/**
@ -909,12 +911,10 @@ static int configure_dma(struct pl022 *pl022)
struct dma_slave_config rx_conf = {
.src_addr = SSP_DR(pl022->phybase),
.direction = DMA_FROM_DEVICE,
.src_maxburst = pl022->vendor->fifodepth >> 1,
};
struct dma_slave_config tx_conf = {
.dst_addr = SSP_DR(pl022->phybase),
.direction = DMA_TO_DEVICE,
.dst_maxburst = pl022->vendor->fifodepth >> 1,
};
unsigned int pages;
int ret;
@ -928,6 +928,54 @@ static int configure_dma(struct pl022 *pl022)
if (!rxchan || !txchan)
return -ENODEV;
/*
* If supplied, the DMA burstsize should equal the FIFO trigger level.
* Notice that the DMA engine uses one-to-one mapping. Since we can
* not trigger on 2 elements this needs explicit mapping rather than
* calculation.
*/
switch (pl022->rx_lev_trig) {
case SSP_RX_1_OR_MORE_ELEM:
rx_conf.src_maxburst = 1;
break;
case SSP_RX_4_OR_MORE_ELEM:
rx_conf.src_maxburst = 4;
break;
case SSP_RX_8_OR_MORE_ELEM:
rx_conf.src_maxburst = 8;
break;
case SSP_RX_16_OR_MORE_ELEM:
rx_conf.src_maxburst = 16;
break;
case SSP_RX_32_OR_MORE_ELEM:
rx_conf.src_maxburst = 32;
break;
default:
rx_conf.src_maxburst = pl022->vendor->fifodepth >> 1;
break;
}
switch (pl022->tx_lev_trig) {
case SSP_TX_1_OR_MORE_EMPTY_LOC:
tx_conf.dst_maxburst = 1;
break;
case SSP_TX_4_OR_MORE_EMPTY_LOC:
tx_conf.dst_maxburst = 4;
break;
case SSP_TX_8_OR_MORE_EMPTY_LOC:
tx_conf.dst_maxburst = 8;
break;
case SSP_TX_16_OR_MORE_EMPTY_LOC:
tx_conf.dst_maxburst = 16;
break;
case SSP_TX_32_OR_MORE_EMPTY_LOC:
tx_conf.dst_maxburst = 32;
break;
default:
tx_conf.dst_maxburst = pl022->vendor->fifodepth >> 1;
break;
}
switch (pl022->read) {
case READING_NULL:
/* Use the same as for writing */
@ -1496,6 +1544,7 @@ static void pump_messages(struct work_struct *work)
* and core will be disabled when giveback() is called in each method
* (poll/interrupt/DMA)
*/
pm_runtime_get_sync(&pl022->adev->dev);
amba_vcore_enable(pl022->adev);
amba_pclk_enable(pl022->adev);
clk_enable(pl022->clk);
@ -1629,17 +1678,57 @@ static int verify_controller_parameters(struct pl022 *pl022,
"Communication mode is configured incorrectly\n");
return -EINVAL;
}
if ((chip_info->rx_lev_trig < SSP_RX_1_OR_MORE_ELEM)
|| (chip_info->rx_lev_trig > SSP_RX_32_OR_MORE_ELEM)) {
switch (chip_info->rx_lev_trig) {
case SSP_RX_1_OR_MORE_ELEM:
case SSP_RX_4_OR_MORE_ELEM:
case SSP_RX_8_OR_MORE_ELEM:
/* These are always OK, all variants can handle this */
break;
case SSP_RX_16_OR_MORE_ELEM:
if (pl022->vendor->fifodepth < 16) {
dev_err(&pl022->adev->dev,
"RX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
}
break;
case SSP_RX_32_OR_MORE_ELEM:
if (pl022->vendor->fifodepth < 32) {
dev_err(&pl022->adev->dev,
"RX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
}
break;
default:
dev_err(&pl022->adev->dev,
"RX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
break;
}
if ((chip_info->tx_lev_trig < SSP_TX_1_OR_MORE_EMPTY_LOC)
|| (chip_info->tx_lev_trig > SSP_TX_32_OR_MORE_EMPTY_LOC)) {
switch (chip_info->tx_lev_trig) {
case SSP_TX_1_OR_MORE_EMPTY_LOC:
case SSP_TX_4_OR_MORE_EMPTY_LOC:
case SSP_TX_8_OR_MORE_EMPTY_LOC:
/* These are always OK, all variants can handle this */
break;
case SSP_TX_16_OR_MORE_EMPTY_LOC:
if (pl022->vendor->fifodepth < 16) {
dev_err(&pl022->adev->dev,
"TX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
}
break;
case SSP_TX_32_OR_MORE_EMPTY_LOC:
if (pl022->vendor->fifodepth < 32) {
dev_err(&pl022->adev->dev,
"TX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
}
break;
default:
dev_err(&pl022->adev->dev,
"TX FIFO Trigger Level is configured incorrectly\n");
return -EINVAL;
break;
}
if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) {
if ((chip_info->ctrl_len < SSP_BITS_4)
@ -1874,6 +1963,9 @@ static int pl022_setup(struct spi_device *spi)
goto err_config_params;
}
pl022->rx_lev_trig = chip_info->rx_lev_trig;
pl022->tx_lev_trig = chip_info->tx_lev_trig;
/* Now set controller state based on controller data */
chip->xfer_type = chip_info->com_mode;
if (!chip_info->cs_control) {
@ -2094,6 +2186,8 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
}
printk(KERN_INFO "pl022: mapped registers from 0x%08x to %p\n",
adev->res.start, pl022->virtbase);
pm_runtime_enable(dev);
pm_runtime_resume(dev);
pl022->clk = clk_get(&adev->dev, NULL);
if (IS_ERR(pl022->clk)) {
@ -2155,6 +2249,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
destroy_queue(pl022);
pl022_dma_remove(pl022);
free_irq(adev->irq[0], pl022);
pm_runtime_disable(&adev->dev);
err_no_irq:
clk_put(pl022->clk);
err_no_clk:

View File

@ -502,7 +502,7 @@ static int __init spi_ppc4xx_of_probe(struct platform_device *op)
goto free_gpios;
}
hw->mapbase = resource.start;
hw->mapsize = resource.end - resource.start + 1;
hw->mapsize = resource_size(&resource);
/* Sanity check */
if (hw->mapsize < sizeof(struct spi_ppc4xx_regs)) {

View File

@ -17,7 +17,7 @@
#include <mach/regs-irq.h>
#include <plat/regs-spi.h>
#include "spi_s3c24xx_fiq.h"
#include "spi-s3c24xx-fiq.h"
.text

View File

@ -1,5 +1,4 @@
/* linux/drivers/spi/spi_s3c24xx.c
*
/*
* Copyright (c) 2006 Ben Dooks
* Copyright 2006-2009 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@ -32,7 +31,7 @@
#include <plat/fiq.h>
#include <asm/fiq.h>
#include "spi_s3c24xx_fiq.h"
#include "spi-s3c24xx-fiq.h"
/**
* s3c24xx_spi_devstate - per device data

View File

@ -1,5 +1,4 @@
/* linux/drivers/spi/spi_s3c64xx.c
*
/*
* Copyright (C) 2009 Samsung Electronics Ltd.
* Jaswinder Singh <jassi.brar@samsung.com>
*

View File

@ -78,7 +78,7 @@ static inline u32 getmiso(struct spi_device *dev)
#define spidelay(x) ndelay(x)
#include "spi_bitbang_txrx.h"
#include "spi-bitbang-txrx.h"
static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)

View File

@ -498,14 +498,14 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
goto err0;
}
if (!request_mem_region(r->start, (r->end - r->start) + 1,
if (!request_mem_region(r->start, resource_size(r),
dev_name(&pdev->dev))) {
ret = -EBUSY;
goto err0;
}
tspi->phys = r->start;
tspi->base = ioremap(r->start, r->end - r->start + 1);
tspi->base = ioremap(r->start, resource_size(r));
if (!tspi->base) {
dev_err(&pdev->dev, "can't ioremap iomem\n");
ret = -ENOMEM;
@ -546,6 +546,7 @@ static int __init spi_tegra_probe(struct platform_device *pdev)
tspi->rx_dma_req.req_sel = spi_tegra_req_sels[pdev->id];
tspi->rx_dma_req.dev = tspi;
master->dev.of_node = pdev->dev.of_node;
ret = spi_register_master(master);
if (ret < 0)
@ -563,7 +564,7 @@ err3:
err2:
iounmap(tspi->base);
err1:
release_mem_region(r->start, (r->end - r->start) + 1);
release_mem_region(r->start, resource_size(r));
err0:
spi_master_put(master);
return ret;
@ -588,17 +589,28 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
iounmap(tspi->base);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(r->start, (r->end - r->start) + 1);
release_mem_region(r->start, resource_size(r));
return 0;
}
MODULE_ALIAS("platform:spi_tegra");
#ifdef CONFIG_OF
static struct of_device_id spi_tegra_of_match_table[] __devinitdata = {
{ .compatible = "nvidia,tegra20-spi", },
{}
};
MODULE_DEVICE_TABLE(of, spi_tegra_of_match_table);
#else /* CONFIG_OF */
#define spi_tegra_of_match_table NULL
#endif /* CONFIG_OF */
static struct platform_driver spi_tegra_driver = {
.driver = {
.name = "spi_tegra",
.owner = THIS_MODULE,
.of_match_table = spi_tegra_of_match_table,
},
.remove = __devexit_p(spi_tegra_remove),
};

View File

@ -1,5 +1,5 @@
/*
* tle62x0.c -- support Infineon TLE62x0 driver chips
* Support Infineon TLE62x0 driver chips
*
* Copyright (c) 2007 Simtec Electronics
* Ben Dooks, <ben@simtec.co.uk>

View File

@ -1,5 +1,5 @@
/*
* spi_txx9.c - TXx9 SPI controller driver.
* TXx9 SPI controller driver.
*
* Based on linux/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
* Copyright (C) 2000-2001 Toshiba Corporation

View File

@ -1,5 +1,5 @@
/*
* spi.c - SPI init/core code
* SPI init/core code
*
* Copyright (C) 2005 David Brownell
*

View File

@ -1,201 +0,0 @@
/* linux/drivers/spi/spi_s3c24xx_gpio.c
*
* Copyright (c) 2006 Ben Dooks
* Copyright (c) 2006 Simtec Electronics
*
* S3C24XX GPIO based SPI driver
*
* 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/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
#include <mach/regs-gpio.h>
#include <mach/spi-gpio.h>
#include <mach/hardware.h>
struct s3c2410_spigpio {
struct spi_bitbang bitbang;
struct s3c2410_spigpio_info *info;
struct platform_device *dev;
};
static inline struct s3c2410_spigpio *spidev_to_sg(struct spi_device *spi)
{
return spi_master_get_devdata(spi->master);
}
static inline void setsck(struct spi_device *dev, int on)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
s3c2410_gpio_setpin(sg->info->pin_clk, on ? 1 : 0);
}
static inline void setmosi(struct spi_device *dev, int on)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
s3c2410_gpio_setpin(sg->info->pin_mosi, on ? 1 : 0);
}
static inline u32 getmiso(struct spi_device *dev)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
return s3c2410_gpio_getpin(sg->info->pin_miso) ? 1 : 0;
}
#define spidelay(x) ndelay(x)
#include "spi_bitbang_txrx.h"
static u32 s3c2410_spigpio_txrx_mode0(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 0, 0, word, bits);
}
static u32 s3c2410_spigpio_txrx_mode1(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 0, 0, word, bits);
}
static u32 s3c2410_spigpio_txrx_mode2(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha0(spi, nsecs, 1, 0, word, bits);
}
static u32 s3c2410_spigpio_txrx_mode3(struct spi_device *spi,
unsigned nsecs, u32 word, u8 bits)
{
return bitbang_txrx_be_cpha1(spi, nsecs, 1, 0, word, bits);
}
static void s3c2410_spigpio_chipselect(struct spi_device *dev, int value)
{
struct s3c2410_spigpio *sg = spidev_to_sg(dev);
if (sg->info && sg->info->chip_select)
(sg->info->chip_select)(sg->info, value);
}
static int s3c2410_spigpio_probe(struct platform_device *dev)
{
struct s3c2410_spigpio_info *info;
struct spi_master *master;
struct s3c2410_spigpio *sp;
int ret;
master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio));
if (master == NULL) {
dev_err(&dev->dev, "failed to allocate spi master\n");
ret = -ENOMEM;
goto err;
}
sp = spi_master_get_devdata(master);
platform_set_drvdata(dev, sp);
/* copy in the plkatform data */
info = sp->info = dev->dev.platform_data;
/* setup spi bitbang adaptor */
sp->bitbang.master = spi_master_get(master);
sp->bitbang.master->bus_num = info->bus_num;
sp->bitbang.master->num_chipselect = info->num_chipselect;
sp->bitbang.chipselect = s3c2410_spigpio_chipselect;
sp->bitbang.txrx_word[SPI_MODE_0] = s3c2410_spigpio_txrx_mode0;
sp->bitbang.txrx_word[SPI_MODE_1] = s3c2410_spigpio_txrx_mode1;
sp->bitbang.txrx_word[SPI_MODE_2] = s3c2410_spigpio_txrx_mode2;
sp->bitbang.txrx_word[SPI_MODE_3] = s3c2410_spigpio_txrx_mode3;
/* set state of spi pins, always assume that the clock is
* available, but do check the MOSI and MISO. */
s3c2410_gpio_setpin(info->pin_clk, 0);
s3c2410_gpio_cfgpin(info->pin_clk, S3C2410_GPIO_OUTPUT);
if (info->pin_mosi < S3C2410_GPH10) {
s3c2410_gpio_setpin(info->pin_mosi, 0);
s3c2410_gpio_cfgpin(info->pin_mosi, S3C2410_GPIO_OUTPUT);
}
if (info->pin_miso != S3C2410_GPA0 && info->pin_miso < S3C2410_GPH10)
s3c2410_gpio_cfgpin(info->pin_miso, S3C2410_GPIO_INPUT);
ret = spi_bitbang_start(&sp->bitbang);
if (ret)
goto err_no_bitbang;
return 0;
err_no_bitbang:
spi_master_put(sp->bitbang.master);
err:
return ret;
}
static int s3c2410_spigpio_remove(struct platform_device *dev)
{
struct s3c2410_spigpio *sp = platform_get_drvdata(dev);
spi_bitbang_stop(&sp->bitbang);
spi_master_put(sp->bitbang.master);
return 0;
}
/* all gpio should be held over suspend/resume, so we should
* not need to deal with this
*/
#define s3c2410_spigpio_suspend NULL
#define s3c2410_spigpio_resume NULL
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:spi_s3c24xx_gpio");
static struct platform_driver s3c2410_spigpio_drv = {
.probe = s3c2410_spigpio_probe,
.remove = s3c2410_spigpio_remove,
.suspend = s3c2410_spigpio_suspend,
.resume = s3c2410_spigpio_resume,
.driver = {
.name = "spi_s3c24xx_gpio",
.owner = THIS_MODULE,
},
};
static int __init s3c2410_spigpio_init(void)
{
return platform_driver_register(&s3c2410_spigpio_drv);
}
static void __exit s3c2410_spigpio_exit(void)
{
platform_driver_unregister(&s3c2410_spigpio_drv);
}
module_init(s3c2410_spigpio_init);
module_exit(s3c2410_spigpio_exit);
MODULE_DESCRIPTION("S3C24XX SPI Driver");
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
MODULE_LICENSE("GPL");

View File

@ -1,5 +1,5 @@
/*
* spidev.c -- simple synchronous userspace interface to SPI devices
* Simple synchronous userspace interface to SPI devices
*
* Copyright (C) 2006 SWAPP
* Andrea Paterniani <a.paterniani@swapp-eng.it>

View File

@ -106,12 +106,12 @@ static struct ep93xx_ac97_info *ep93xx_ac97_info;
static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = {
.name = "ac97-pcm-out",
.dma_port = EP93XX_DMA_M2P_PORT_AAC1,
.dma_port = EP93XX_DMA_AAC1,
};
static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = {
.name = "ac97-pcm-in",
.dma_port = EP93XX_DMA_M2P_PORT_AAC1,
.dma_port = EP93XX_DMA_AAC1,
};
static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,

View File

@ -70,11 +70,11 @@ struct ep93xx_i2s_info {
struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
[SNDRV_PCM_STREAM_PLAYBACK] = {
.name = "i2s-pcm-out",
.dma_port = EP93XX_DMA_M2P_PORT_I2S1,
.dma_port = EP93XX_DMA_I2S1,
},
[SNDRV_PCM_STREAM_CAPTURE] = {
.name = "i2s-pcm-in",
.dma_port = EP93XX_DMA_M2P_PORT_I2S1,
.dma_port = EP93XX_DMA_I2S1,
},
};

View File

@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
@ -53,43 +54,34 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
struct ep93xx_runtime_data
{
struct ep93xx_dma_m2p_client cl;
struct ep93xx_pcm_dma_params *params;
int pointer_bytes;
struct tasklet_struct period_tasklet;
int periods;
struct ep93xx_dma_buffer buf[32];
int period_bytes;
struct dma_chan *dma_chan;
struct ep93xx_dma_data dma_data;
};
static void ep93xx_pcm_period_elapsed(unsigned long data)
static void ep93xx_pcm_dma_callback(void *data)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
struct snd_pcm_substream *substream = data;
struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
rtd->pointer_bytes += rtd->period_bytes;
rtd->pointer_bytes %= rtd->period_bytes * rtd->periods;
snd_pcm_period_elapsed(substream);
}
static void ep93xx_pcm_buffer_started(void *cookie,
struct ep93xx_dma_buffer *buf)
static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
{
}
struct ep93xx_dma_data *data = filter_param;
static void ep93xx_pcm_buffer_finished(void *cookie,
struct ep93xx_dma_buffer *buf,
int bytes, int error)
{
struct snd_pcm_substream *substream = cookie;
struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
if (buf == rtd->buf + rtd->periods - 1)
rtd->pointer_bytes = 0;
else
rtd->pointer_bytes += buf->size;
if (!error) {
ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
tasklet_schedule(&rtd->period_tasklet);
} else {
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
if (data->direction == ep93xx_dma_chan_direction(chan)) {
chan->private = data;
return true;
}
return false;
}
static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
@ -98,30 +90,38 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
struct snd_soc_dai *cpu_dai = soc_rtd->cpu_dai;
struct ep93xx_pcm_dma_params *dma_params;
struct ep93xx_runtime_data *rtd;
dma_cap_mask_t mask;
int ret;
dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
ret = snd_pcm_hw_constraint_integer(substream->runtime,
SNDRV_PCM_HW_PARAM_PERIODS);
if (ret < 0)
return ret;
snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
if (!rtd)
return -ENOMEM;
memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
rtd->period_tasklet.data = (unsigned long)substream;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
dma_cap_set(DMA_CYCLIC, mask);
rtd->cl.name = dma_params->name;
rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
rtd->cl.cookie = substream;
rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
ret = ep93xx_dma_m2p_client_register(&rtd->cl);
if (ret < 0) {
dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
rtd->dma_data.port = dma_params->dma_port;
rtd->dma_data.name = dma_params->name;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
rtd->dma_data.direction = DMA_TO_DEVICE;
else
rtd->dma_data.direction = DMA_FROM_DEVICE;
rtd->dma_chan = dma_request_channel(mask, ep93xx_pcm_dma_filter,
&rtd->dma_data);
if (!rtd->dma_chan) {
kfree(rtd);
return ret;
return -EINVAL;
}
substream->runtime->private_data = rtd;
@ -132,31 +132,52 @@ static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
{
struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
ep93xx_dma_m2p_client_unregister(&rtd->cl);
dma_release_channel(rtd->dma_chan);
kfree(rtd);
return 0;
}
static int ep93xx_pcm_dma_submit(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct ep93xx_runtime_data *rtd = runtime->private_data;
struct dma_chan *chan = rtd->dma_chan;
struct dma_device *dma_dev = chan->device;
struct dma_async_tx_descriptor *desc;
rtd->pointer_bytes = 0;
desc = dma_dev->device_prep_dma_cyclic(chan, runtime->dma_addr,
rtd->period_bytes * rtd->periods,
rtd->period_bytes,
rtd->dma_data.direction);
if (!desc)
return -EINVAL;
desc->callback = ep93xx_pcm_dma_callback;
desc->callback_param = substream;
dmaengine_submit(desc);
return 0;
}
static void ep93xx_pcm_dma_flush(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct ep93xx_runtime_data *rtd = runtime->private_data;
dmaengine_terminate_all(rtd->dma_chan);
}
static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct ep93xx_runtime_data *rtd = runtime->private_data;
size_t totsize = params_buffer_bytes(params);
size_t period = params_period_bytes(params);
int i;
snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
runtime->dma_bytes = totsize;
rtd->periods = (totsize + period - 1) / period;
for (i = 0; i < rtd->periods; i++) {
rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
rtd->buf[i].size = period;
if ((i + 1) * period > totsize)
rtd->buf[i].size = totsize - (i * period);
}
rtd->periods = params_periods(params);
rtd->period_bytes = params_period_bytes(params);
return 0;
}
@ -168,24 +189,20 @@ static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
int ret;
int i;
ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
rtd->pointer_bytes = 0;
for (i = 0; i < rtd->periods; i++)
ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
ret = ep93xx_pcm_dma_submit(substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ep93xx_dma_m2p_flush(&rtd->cl);
ep93xx_pcm_dma_flush(substream);
break;
default: