From: David Brownell <david-b@pacbell.net>
To: linux-omap-open-source@linux.omap.com
Subject: [patch linux-omap-git 2/2] omap2_mcspi fixes + cleanups
Date: Wed, 23 May 2007 20:46:12 -0700 [thread overview]
Message-ID: <200705232046.12406.david-b@pacbell.net> (raw)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 21438 bytes --]
McSPI functional updates:
- Implement the spi_transfer.delay_usecs mechanism (previously omitted).
- Remove strange per-device <asm/arch/mcspi.h> hookery ... it's not even
correct as a per-device config. We *always* want "single channel" mode
(in "keep chipselect active" mode); and if we used "turbo", it would
be a per-transfer option (as an rx-only double buffering tweak).
- When enabling/disabling a channel, old value is irrelevant; don't read.
- Sanity check spi->mode bits, and reject ones we don't support.
- Streamline DMA channel selection: do it once during probe(), using static
tables; smaller, faster. OMAP 2430 still needs changes here, minimally for
the third SPI controller. (Board init should change too, to not assume
all SPI controllers are used on every board...)
- Remove #ifdefs around doing reset on driver startup ... enable clocks
so we can do that (!), and turn on auto-idle.
- Waste less time enabling/disabling the clocks while working the queue.
- Flag DMA channels as freed when we do so ... so they can't get reused
later (when another driver may own them).
- Minor PIO fix: don't need to verify TX side completed except for TX_ONLY
mode, since RX completed implies TX completed.
- Remove bogus code which always dropped chipselect after the last RX_ONLY
word (rather than leaving it enabled).
- Move error checks out of work loop into setup() and transfer(), so that
they're reported ASAP rather than as mysterious transfer errors).
Plus a handful of cleanups: whitespace fixes, comments.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
drivers/spi/omap2_mcspi.c | 348 +++++++++++++++++++++++++++-------------------
1 file changed, 205 insertions(+), 143 deletions(-)
--- h4.orig/drivers/spi/omap2_mcspi.c 2007-05-23 20:13:15.000000000 -0700
+++ h4/drivers/spi/omap2_mcspi.c 2007-05-23 20:13:17.000000000 -0700
@@ -2,8 +2,8 @@
* OMAP2 McSPI controller driver
*
* Copyright (C) 2005, 2006 Nokia Corporation
- * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
- * Juha Yrjölä <juha.yrjola@nokia.com>
+ * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and
+ * Juha Yrjölä <juha.yrjola@nokia.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
@@ -36,7 +36,6 @@
#include <asm/io.h>
#include <asm/arch/dma.h>
-#include <asm/arch/mcspi.h>
#include <asm/arch/clock.h>
#define OMAP2_MCSPI_MAX_FREQ 48000000
@@ -49,12 +48,17 @@
#define OMAP2_MCSPI_WAKEUPENABLE 0x20
#define OMAP2_MCSPI_SYST 0x24
#define OMAP2_MCSPI_MODULCTRL 0x28
+
+/* per-channel banks, 0x14 bytes each, first is: */
#define OMAP2_MCSPI_CHCONF0 0x2c
#define OMAP2_MCSPI_CHSTAT0 0x30
#define OMAP2_MCSPI_CHCTRL0 0x34
#define OMAP2_MCSPI_TX0 0x38
#define OMAP2_MCSPI_RX0 0x3c
+/* per-register bitmasks: */
+
+#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE (1 << 0)
#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
#define OMAP2_MCSPI_SYSSTATUS_RESETDONE (1 << 0)
@@ -79,13 +83,13 @@
#define OMAP2_MCSPI_CHCONF_TURBO (1 << 19)
#define OMAP2_MCSPI_CHCONF_FORCE (1 << 20)
-
#define OMAP2_MCSPI_CHSTAT_RXS (1 << 0)
#define OMAP2_MCSPI_CHSTAT_TXS (1 << 1)
#define OMAP2_MCSPI_CHSTAT_EOT (1 << 2)
#define OMAP2_MCSPI_CHCTRL_EN (1 << 0)
+
/* We have 2 DMA channels per CS, one for RX and one for TX */
struct omap2_mcspi_dma {
int dma_tx_channel;
@@ -177,8 +181,7 @@ static void omap2_mcspi_set_enable(const
{
u32 l;
- l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0);
- MOD_REG_BIT(l, OMAP2_MCSPI_CHCTRL_EN, enable);
+ l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0;
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l);
}
@@ -191,24 +194,26 @@ static void omap2_mcspi_force_cs(struct
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
}
-static void omap2_mcspi_set_master_mode(struct spi_device *spi, int single_channel)
+static void omap2_mcspi_set_master_mode(struct spi_master *master)
{
u32 l;
- /* Need reset when switching from slave mode */
- l = mcspi_read_reg(spi->master, OMAP2_MCSPI_MODULCTRL);
+ /* setup when switching from (reset default) slave mode
+ * to single-channel master mode
+ */
+ l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL);
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_STEST, 0);
MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_MS, 0);
- MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, single_channel);
- mcspi_write_reg(spi->master, OMAP2_MCSPI_MODULCTRL, l);
+ MOD_REG_BIT(l, OMAP2_MCSPI_MODULCTRL_SINGLE, 1);
+ mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l);
}
-static void omap2_mcspi_txrx_dma(struct spi_device *spi,
- struct spi_transfer *xfer)
+static void
+omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer)
{
- struct omap2_mcspi * mcspi;
- struct omap2_mcspi_cs * cs = spi->controller_state;
- struct omap2_mcspi_dma * mcspi_dma;
+ struct omap2_mcspi *mcspi;
+ struct omap2_mcspi_cs *cs = spi->controller_state;
+ struct omap2_mcspi_dma *mcspi_dma;
unsigned int count, c;
unsigned long base, tx_reg, rx_reg;
int word_len, data_type, element_count;
@@ -339,13 +344,13 @@ static int mcspi_wait_for_reg_bit(unsign
return 0;
}
-static void omap2_mcspi_txrx_pio(struct spi_device *spi,
- struct spi_transfer *xfer)
+static void
+omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer)
{
struct omap2_mcspi *mcspi;
struct omap2_mcspi_cs *cs = spi->controller_state;
unsigned int count, c;
- u32 l;
+ u32 l;
unsigned long base, tx_reg, rx_reg, chstat_reg;
int word_len;
@@ -371,7 +376,11 @@ static void omap2_mcspi_txrx_pio(struct
rx_reg = base + OMAP2_MCSPI_RX0;
chstat_reg = base + OMAP2_MCSPI_CHSTAT0;
- /* RX_ONLY mode needs dummy data in TX reg */
+ /* RX_ONLY mode needs dummy data in TX reg. If we were using
+ * TURBO mode (double buffered) we'd need to disable the channel
+ * before reading the penultimate word ... so TURBO wouldn't be an
+ * option except for the last transfer, else if cs_change is set.
+ */
if (xfer->tx_buf == NULL)
__raw_writel(0, tx_reg);
@@ -401,8 +410,6 @@ static void omap2_mcspi_txrx_pio(struct
dev_err(&spi->dev, "RXS timed out\n");
goto out;
}
- if (c == 0 && tx == NULL)
- omap2_mcspi_set_enable(spi, 0);
*rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %02x\n",
@@ -436,8 +443,6 @@ static void omap2_mcspi_txrx_pio(struct
dev_err(&spi->dev, "RXS timed out\n");
goto out;
}
- if (c == 0 && tx == NULL)
- omap2_mcspi_set_enable(spi, 0);
*rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %04x\n",
@@ -471,8 +476,6 @@ static void omap2_mcspi_txrx_pio(struct
dev_err(&spi->dev, "RXS timed out\n");
goto out;
}
- if (c == 0 && tx == NULL)
- omap2_mcspi_set_enable(spi, 0);
*rx++ = __raw_readl(rx_reg);
#ifdef VERBOSE
dev_dbg(&spi->dev, "read-%d %04x\n",
@@ -482,7 +485,8 @@ static void omap2_mcspi_txrx_pio(struct
}
}
- if (xfer->tx_buf != NULL) {
+ /* for TX_ONLY mode, be sure all words have shifted out */
+ if (xfer->rx_buf == NULL) {
if (mcspi_wait_for_reg_bit(chstat_reg,
OMAP2_MCSPI_CHSTAT_TXS) < 0) {
dev_err(&spi->dev, "TXS timed out\n");
@@ -496,11 +500,11 @@ out:
}
}
+/* called only when no transfer is active to this device */
static int omap2_mcspi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct omap2_mcspi_cs *cs = spi->controller_state;
- struct omap2_mcspi_device_config *conf;
struct omap2_mcspi *mcspi;
u32 l = 0, div = 0;
u8 word_len = spi->bits_per_word;
@@ -509,23 +513,9 @@ static int omap2_mcspi_setup_transfer(st
if (t != NULL && t->bits_per_word)
word_len = t->bits_per_word;
- if (!word_len)
- word_len = 8;
- if (spi->bits_per_word > 32)
- return -EINVAL;
cs->word_len = word_len;
- conf = (struct omap2_mcspi_device_config *) spi->controller_data;
-
- clk_enable(mcspi->ick);
- clk_enable(mcspi->fck);
-
- if (conf->single_channel == 1)
- omap2_mcspi_set_master_mode(spi, 1);
- else
- omap2_mcspi_set_master_mode(spi, 0);
-
if (spi->max_speed_hz) {
while (div <= 15 && (OMAP2_MCSPI_MAX_FREQ / (1 << div))
> spi->max_speed_hz)
@@ -533,25 +523,29 @@ static int omap2_mcspi_setup_transfer(st
} else
div = 15;
- if (spi->chip_select > 3 || word_len < 4 || word_len > 32 || div > 15) {
- dev_err(&spi->dev, "Invalid McSPI channel setting\n");
- clk_disable(mcspi->fck);
- clk_disable(mcspi->ick);
- return -EINVAL;
- }
-
l = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
- l &= ~OMAP2_MCSPI_CHCONF_IS;
- l &= ~OMAP2_MCSPI_CHCONF_DPE1;
+
+ /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS
+ * REVISIT: this controller could support SPI_3WIRE mode.
+ */
+ l &= ~(OMAP2_MCSPI_CHCONF_IS|OMAP2_MCSPI_CHCONF_DPE1);
l |= OMAP2_MCSPI_CHCONF_DPE0;
+
+ /* wordlength */
l &= ~OMAP2_MCSPI_CHCONF_WL_MASK;
l |= (word_len - 1) << 7;
+
+ /* set chipselect polarity; manage with FORCE */
if (!(spi->mode & SPI_CS_HIGH))
- l |= OMAP2_MCSPI_CHCONF_EPOL;
+ l |= OMAP2_MCSPI_CHCONF_EPOL; /* active-low; normal */
else
l &= ~OMAP2_MCSPI_CHCONF_EPOL;
+
+ /* set clock divisor */
l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK;
l |= div << 2;
+
+ /* set SPI mode 0..3 */
if (spi->mode & SPI_CPOL)
l |= OMAP2_MCSPI_CHCONF_POL;
else
@@ -560,15 +554,13 @@ static int omap2_mcspi_setup_transfer(st
l |= OMAP2_MCSPI_CHCONF_PHA;
else
l &= ~OMAP2_MCSPI_CHCONF_PHA;
+
mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, l);
- dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s inverted\n",
+ dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n",
OMAP2_MCSPI_MAX_FREQ / (1 << div),
(spi->mode & SPI_CPHA) ? "trailing" : "leading",
- (spi->mode & SPI_CPOL) ? "" : "not");
-
- clk_disable(mcspi->fck);
- clk_disable(mcspi->ick);
+ (spi->mode & SPI_CPOL) ? "inverted" : "normal");
return 0;
}
@@ -605,61 +597,21 @@ static void omap2_mcspi_dma_tx_callback(
static int omap2_mcspi_request_dma(struct spi_device *spi)
{
- int rx_dev_id, tx_dev_id;
struct spi_master *master = spi->master;
struct omap2_mcspi *mcspi;
struct omap2_mcspi_dma *mcspi_dma;
mcspi = spi_master_get_devdata(master);
- mcspi_dma = &(mcspi->dma_channels[spi->chip_select]);
-
- if (master->bus_num == 1) {
- switch (spi->chip_select) {
- case 0:
- rx_dev_id = OMAP24XX_DMA_SPI1_RX0;
- tx_dev_id = OMAP24XX_DMA_SPI1_TX0;
- break;
- case 1:
- rx_dev_id = OMAP24XX_DMA_SPI1_RX1;
- tx_dev_id = OMAP24XX_DMA_SPI1_TX1;
- break;
- case 2:
- rx_dev_id = OMAP24XX_DMA_SPI1_RX2;
- tx_dev_id = OMAP24XX_DMA_SPI1_TX2;
- break;
- case 3:
- rx_dev_id = OMAP24XX_DMA_SPI1_RX3;
- tx_dev_id = OMAP24XX_DMA_SPI1_TX3;
- break;
- default:
- return -EINVAL;
- }
- } else if (master->bus_num == 2) {
- /* McSPI 2 has 1 chipselect */
- switch (spi->chip_select) {
- case 0:
- rx_dev_id = OMAP24XX_DMA_SPI2_RX0;
- tx_dev_id = OMAP24XX_DMA_SPI2_TX0;
- break;
- case 1:
- rx_dev_id = OMAP24XX_DMA_SPI2_RX1;
- tx_dev_id = OMAP24XX_DMA_SPI2_TX1;
- break;
- default:
- return -EINVAL;
- }
- } else
- return -EINVAL;
-
+ mcspi_dma = mcspi->dma_channels + spi->chip_select;
- if (omap_request_dma(rx_dev_id, "McSPI RX",
+ if (omap_request_dma(mcspi_dma->dma_rx_sync_dev, "McSPI RX",
omap2_mcspi_dma_rx_callback, spi,
&mcspi_dma->dma_rx_channel)) {
dev_err(&spi->dev, "no RX DMA channel for McSPI\n");
return -EAGAIN;
}
- if (omap_request_dma(tx_dev_id, "McSPI TX",
+ if (omap_request_dma(mcspi_dma->dma_tx_sync_dev, "McSPI TX",
omap2_mcspi_dma_tx_callback, spi,
&mcspi_dma->dma_tx_channel)) {
omap_free_dma(mcspi_dma->dma_rx_channel);
@@ -668,15 +620,15 @@ static int omap2_mcspi_request_dma(struc
return -EAGAIN;
}
- mcspi_dma->dma_rx_sync_dev = rx_dev_id;
- mcspi_dma->dma_tx_sync_dev = tx_dev_id;
-
init_completion(&mcspi_dma->dma_rx_completion);
init_completion(&mcspi_dma->dma_tx_completion);
return 0;
}
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
static int omap2_mcspi_setup(struct spi_device *spi)
{
int ret;
@@ -684,6 +636,20 @@ static int omap2_mcspi_setup(struct spi_
struct omap2_mcspi_dma *mcspi_dma;
struct omap2_mcspi_cs *cs = spi->controller_state;
+ if (spi->mode & ~MODEBITS) {
+ dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ spi->mode & ~MODEBITS);
+ return -EINVAL;
+ }
+
+ if (spi->bits_per_word == 0)
+ spi->bits_per_word = 8;
+ else if (spi->bits_per_word < 4 || spi->bits_per_word > 32) {
+ dev_dbg(&spi->dev, "setup: unsupported %d bit words\n",
+ spi->bits_per_word);
+ return -EINVAL;
+ }
+
mcspi = spi_master_get_devdata(spi->master);
mcspi_dma = &mcspi->dma_channels[spi->chip_select];
@@ -701,7 +667,13 @@ static int omap2_mcspi_setup(struct spi_
return ret;
}
- return omap2_mcspi_setup_transfer(spi, NULL);
+ clk_enable(mcspi->ick);
+ clk_enable(mcspi->fck);
+ ret = omap2_mcspi_setup_transfer(spi, NULL);
+ clk_disable(mcspi->fck);
+ clk_disable(mcspi->ick);
+
+ return ret;
}
static void omap2_mcspi_cleanup(struct spi_device *spi)
@@ -715,20 +687,32 @@ static void omap2_mcspi_cleanup(struct s
if (spi->controller_state != NULL)
kfree(spi->controller_state);
- if (mcspi_dma->dma_rx_channel != -1
- && mcspi_dma->dma_tx_channel != -1) {
- omap_free_dma(mcspi_dma->dma_tx_channel);
+ if (mcspi_dma->dma_rx_channel != -1) {
omap_free_dma(mcspi_dma->dma_rx_channel);
+ mcspi_dma->dma_rx_channel = -1;
+ }
+ if (mcspi_dma->dma_tx_channel != -1) {
+ omap_free_dma(mcspi_dma->dma_tx_channel);
+ mcspi_dma->dma_tx_channel = -1;
}
}
static void omap2_mcspi_work(struct work_struct *work)
{
struct omap2_mcspi *mcspi;
- unsigned long flags;
mcspi = container_of(work, struct omap2_mcspi, work);
- spin_lock_irqsave(&mcspi->lock, flags);
+ spin_lock_irq(&mcspi->lock);
+
+ clk_enable(mcspi->ick);
+ clk_enable(mcspi->fck);
+
+ /* We only enable one channel at a time -- the one whose message is
+ * at the head of the queue -- although this controller would gladly
+ * arbitrate among multiple channels. This corresponds to "single
+ * channel" master mode. As a side effect, we need to manage the
+ * chipselect with the FORCE bit ... CS != channel enable.
+ */
while (!list_empty(&mcspi->msg_queue)) {
struct spi_message *m;
struct spi_device *spi;
@@ -743,11 +727,11 @@ static void omap2_mcspi_work(struct work
queue);
list_del_init(&m->queue);
- spin_unlock_irqrestore(&mcspi->lock, flags);
+ spin_unlock_irq(&mcspi->lock);
spi = m->spi;
- conf = (struct omap2_mcspi_device_config *) spi->controller_data;
- cs = (struct omap2_mcspi_cs *) spi->controller_state;
+ conf = spi->controller_data;
+ cs = spi->controller_state;
list_for_each_entry(t, &m->transfers, transfer_list) {
if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
@@ -763,9 +747,6 @@ static void omap2_mcspi_work(struct work
par_override = 0;
}
- clk_enable(mcspi->ick);
- clk_enable(mcspi->fck);
-
if (!cs_active) {
omap2_mcspi_force_cs(spi, 1);
cs_active = 1;
@@ -777,20 +758,17 @@ static void omap2_mcspi_work(struct work
else
omap2_mcspi_txrx_pio(spi, t);
+ if (t->delay_usecs)
+ udelay(t->delay_usecs);
+
+ /* this ignores the "leave it on after last xfer" hint */
if (t->cs_change) {
- /* In the last transfer entry the flag means
- * _leave_ CS on */
- if (t->transfer_list.next != &m->transfers)
- omap2_mcspi_force_cs(spi, 0);
+ omap2_mcspi_force_cs(spi, 0);
cs_active = 0;
}
- clk_disable(mcspi->ick);
- clk_disable(mcspi->fck);
}
- clk_enable(mcspi->ick);
- clk_enable(mcspi->fck);
- /* Restore defaults they are overriden */
+ /* Restore defaults if they were overriden */
if (par_override) {
par_override = 0;
status = omap2_mcspi_setup_transfer(spi, NULL);
@@ -798,25 +776,55 @@ static void omap2_mcspi_work(struct work
if (cs_active)
omap2_mcspi_force_cs(spi, 0);
- clk_disable(mcspi->ick);
- clk_disable(mcspi->fck);
m->status = status;
m->complete(m->context);
- spin_lock_irqsave(&mcspi->lock, flags);
+ spin_lock_irq(&mcspi->lock);
}
- spin_unlock_irqrestore(&mcspi->lock, flags);
+
+ clk_disable(mcspi->fck);
+ clk_disable(mcspi->ick);
+
+ spin_unlock_irq(&mcspi->lock);
}
static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
{
struct omap2_mcspi *mcspi;
unsigned long flags;
+ struct spi_transfer *t;
m->actual_length = 0;
m->status = 0;
+ /* reject invalid messages and transfers */
+ if (list_empty(&m->transfers) || !m->complete)
+ return -EINVAL;
+ list_for_each_entry(t, &m->transfers, transfer_list) {
+ if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ
+ || (t->len && !(t->rx_buf || t->tx_buf))
+ || (t->bits_per_word &&
+ ( t->bits_per_word < 4
+ || t->bits_per_word > 32))) {
+ dev_dbg(&spi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n",
+ t->speed_hz,
+ t->len,
+ t->rx_buf ? "rx" : "",
+ t->tx_buf ? "tx" : "",
+ t->bits_per_word);
+ return -EINVAL;
+ }
+ if (t->speed_hz && t->speed_hz < OMAP2_MCSPI_MAX_FREQ/(1<<16)) {
+ dev_dbg(&spi->dev, "%d Hz max exceeds %d\n",
+ t->speed_hz,
+ t->speed_hz < OMAP2_MCSPI_MAX_FREQ/(1<<16));
+ return -EINVAL;
+ }
+
+ /* REVISIT move dma mapping to here */
+ }
+
mcspi = spi_master_get_devdata(spi->master);
spin_lock_irqsave(&mcspi->lock, flags);
@@ -828,27 +836,79 @@ static int omap2_mcspi_transfer(struct s
return 0;
}
-static int __init omap2_mcspi_reset(struct spi_master *master)
+static int __init omap2_mcspi_reset(struct omap2_mcspi *mcspi)
{
-#if 0
+ struct spi_master *master = mcspi->master;
+ u32 tmp;
+
+ clk_enable(mcspi->ick);
+ clk_enable(mcspi->fck);
+
mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
- while (!(mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS) & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
-#else
+ do {
+ tmp = mcspi_read_reg(master, OMAP2_MCSPI_SYSSTATUS);
+ } while (!(tmp & OMAP2_MCSPI_SYSSTATUS_RESETDONE));
+
+ mcspi_write_reg(master, OMAP2_MCSPI_SYSCONFIG,
+ // (3 << 8) | (2 << 3) |
+ OMAP2_MCSPI_SYSCONFIG_AUTOIDLE);
+
+ omap2_mcspi_set_master_mode(master);
+
+ clk_disable(mcspi->fck);
+ clk_disable(mcspi->ick);
return 0;
-#endif
}
+static u8 __initdata spi1_rxdma_id [] = {
+ OMAP24XX_DMA_SPI1_RX0,
+ OMAP24XX_DMA_SPI1_RX1,
+ OMAP24XX_DMA_SPI1_RX2,
+ OMAP24XX_DMA_SPI1_RX3,
+};
+
+static u8 __initdata spi1_txdma_id [] = {
+ OMAP24XX_DMA_SPI1_TX0,
+ OMAP24XX_DMA_SPI1_TX1,
+ OMAP24XX_DMA_SPI1_TX2,
+ OMAP24XX_DMA_SPI1_TX3,
+};
+
+static u8 __initdata spi2_rxdma_id[] = {
+ OMAP24XX_DMA_SPI2_RX0,
+ OMAP24XX_DMA_SPI2_RX1,
+};
+
+static u8 __initdata spi2_txdma_id[] = {
+ OMAP24XX_DMA_SPI2_TX0,
+ OMAP24XX_DMA_SPI2_TX1,
+};
+
static int __init omap2_mcspi_probe(struct platform_device *pdev)
{
- struct spi_master *master;
- struct omap2_mcspi_platform_config *pdata = pdev->dev.platform_data;
- struct omap2_mcspi *mcspi;
- struct resource *r;
- int status = 0, i;
+ struct spi_master *master;
+ struct omap2_mcspi *mcspi;
+ struct resource *r;
+ int status = 0, i;
+ const u8 *rxdma_id, *txdma_id;
+ unsigned num_chipselect;
- if (!pdata)
+ switch (pdev->id) {
+ case 1:
+ rxdma_id = spi1_rxdma_id;
+ txdma_id = spi1_txdma_id;
+ num_chipselect = 4;
+ break;
+ case 2:
+ rxdma_id = spi2_rxdma_id;
+ txdma_id = spi2_txdma_id;
+ num_chipselect = 2;
+ break;
+ /* REVISIT omap2430 has a third McSPI ... */
+ default:
return -EINVAL;
+ }
master = spi_alloc_master(&pdev->dev, sizeof *mcspi);
if (master == NULL) {
@@ -862,7 +922,7 @@ static int __init omap2_mcspi_probe(stru
master->setup = omap2_mcspi_setup;
master->transfer = omap2_mcspi_transfer;
master->cleanup = omap2_mcspi_cleanup;
- master->num_chipselect = pdata->num_cs;
+ master->num_chipselect = num_chipselect;
dev_set_drvdata(&pdev->dev, master);
@@ -907,13 +967,15 @@ static int __init omap2_mcspi_probe(stru
if (mcspi->dma_channels == NULL)
goto err3;
- for (i = 0; i < master->num_chipselect; i++) {
+ for (i = 0; i < num_chipselect; i++) {
mcspi->dma_channels[i].dma_rx_channel = -1;
+ mcspi->dma_channels[i].dma_rx_sync_dev = rxdma_id[i];
mcspi->dma_channels[i].dma_tx_channel = -1;
+ mcspi->dma_channels[i].dma_tx_sync_dev = txdma_id[i];
}
- if (omap2_mcspi_reset(master) < 0)
- goto err4;
+ if (omap2_mcspi_reset(mcspi) < 0)
+ goto err4;
status = spi_register_master(master);
if (status < 0)
next reply other threads:[~2007-05-24 3:46 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-05-24 3:46 David Brownell [this message]
2007-05-24 9:21 ` [patch linux-omap-git 2/2] omap2_mcspi fixes + cleanups Imre Deak
2007-05-24 16:34 ` David Brownell
2007-05-25 0:39 ` Tony Lindgren
2007-05-25 6:59 ` Imre Deak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200705232046.12406.david-b@pacbell.net \
--to=david-b@pacbell.net \
--cc=linux-omap-open-source@linux.omap.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.