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:
Коммит
7235dd74a4
|
@ -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 */
|
||||
};
|
|
@ -0,0 +1,5 @@
|
|||
NVIDIA Tegra 2 SPI device
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "nvidia,tegra20-spi".
|
||||
- gpios : should specify GPIOs used for chipselect.
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
|
@ -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);
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
||||
|
|
|
@ -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 ...
|
||||
|
|
|
@ -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__ */
|
|
@ -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;
|
|
@ -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
|
|
@ -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)
|
||||
*
|
|
@ -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);
|
|
@ -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;
|
|
@ -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,
|
|
@ -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>
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -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;
|
|
@ -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;
|
|
@ -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);
|
|
@ -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 {
|
|
@ -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) \
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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,
|
|
@ -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)
|
||||
{
|
|
@ -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>
|
|
@ -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>
|
||||
*
|
|
@ -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);
|
|
@ -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);
|
||||
|
|
@ -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:
|
|
@ -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)) {
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -1,5 +1,4 @@
|
|||
/* linux/drivers/spi/spi_s3c64xx.c
|
||||
*
|
||||
/*
|
||||
* Copyright (C) 2009 Samsung Electronics Ltd.
|
||||
* Jaswinder Singh <jassi.brar@samsung.com>
|
||||
*
|
|
@ -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)
|
|
@ -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),
|
||||
};
|
|
@ -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>
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* spi.c - SPI init/core code
|
||||
* SPI init/core code
|
||||
*
|
||||
* Copyright (C) 2005 David Brownell
|
||||
*
|
||||
|
|
|
@ -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");
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Загрузка…
Ссылка в новой задаче