Skip to content

Commit

Permalink
Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6
Browse files Browse the repository at this point in the history
Pull misc SPI device driver bug fixes from Grant Likely.

* tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6:
  spi/spi-bfin5xx: Fix flush of last bit after each spi transfer
  spi/spi-bfin5xx: fix reversed if condition in interrupt mode
  spi/spi_bfin_sport: drop bits_per_word from client data
  spi/bfin_spi: drop bits_per_word from client data
  spi/spi-bfin-sport: move word length setup to transfer handler
  spi/bfin5xx: rename config macro name for bfin5xx spi controller driver
  spi/pl022: Allow request for higher frequency than maximum possible
  spi/bcm63xx: set master driver mode_bits.
  spi/bcm63xx: don't use the stopping state
  spi/bcm63xx: convert to the pump message infrastructure
  spi/spi-ep93xx.c: use dma_transfer_direction instead of dma_data_direction
  spi: fix spi.h kernel-doc warning
  spi/pl022: Fix calculate_effective_freq()
  spi/pl022: Fix range checking for bits per word
  • Loading branch information
Linus Torvalds committed Apr 28, 2012
2 parents 9f7e2f9 + 2431a81 commit 84c6a81
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 128 deletions.
2 changes: 1 addition & 1 deletion drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips.

config SPI_BFIN
config SPI_BFIN5XX
tristate "SPI controller driver for ADI Blackfin5xx"
depends on BLACKFIN
help
Expand Down
2 changes: 1 addition & 1 deletion drivers/spi/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.o
obj-$(CONFIG_SPI_BFIN) += spi-bfin5xx.o
obj-$(CONFIG_SPI_BFIN5XX) += 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
Expand Down
163 changes: 92 additions & 71 deletions drivers/spi/spi-bcm63xx.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Broadcom BCM63xx SPI controller support
*
* Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org>
* Copyright (C) 2009-2012 Florian Fainelli <florian@openwrt.org>
* Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
*
* This program is free software; you can redistribute it and/or
Expand Down Expand Up @@ -30,15 +30,15 @@
#include <linux/spi/spi.h>
#include <linux/completion.h>
#include <linux/err.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>

#include <bcm63xx_dev_spi.h>

#define PFX KBUILD_MODNAME
#define DRV_VER "0.1.2"

struct bcm63xx_spi {
spinlock_t lock;
int stopping;
struct completion done;

void __iomem *regs;
Expand Down Expand Up @@ -96,17 +96,12 @@ static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
{ 391000, SPI_CLK_0_391MHZ }
};

static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
static int bcm63xx_spi_check_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
u8 bits_per_word;
u8 clk_cfg, reg;
u32 hz;
int i;

bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
hz = (t) ? t->speed_hz : spi->max_speed_hz;
if (bits_per_word != 8) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word);
Expand All @@ -119,6 +114,19 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
return -EINVAL;
}

return 0;
}

static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
u32 hz;
u8 clk_cfg, reg;
int i;

hz = (t) ? t->speed_hz : spi->max_speed_hz;

/* Find the closest clock configuration */
for (i = 0; i < SPI_CLK_MASK; i++) {
if (hz <= bcm63xx_spi_freq_table[i][0]) {
Expand All @@ -139,8 +147,6 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
bcm_spi_writeb(bs, reg, SPI_CLK_CFG);
dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n",
clk_cfg, hz);

return 0;
}

/* the spi->mode bits understood by this driver: */
Expand All @@ -153,9 +159,6 @@ static int bcm63xx_spi_setup(struct spi_device *spi)

bs = spi_master_get_devdata(spi->master);

if (bs->stopping)
return -ESHUTDOWN;

if (!spi->bits_per_word)
spi->bits_per_word = 8;

Expand All @@ -165,7 +168,7 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
return -EINVAL;
}

ret = bcm63xx_spi_setup_transfer(spi, NULL);
ret = bcm63xx_spi_check_transfer(spi, NULL);
if (ret < 0) {
dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
spi->mode & ~MODEBITS);
Expand All @@ -190,28 +193,29 @@ static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
bs->remaining_bytes -= size;
}

static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
struct spi_transfer *t)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
u16 msg_ctl;
u16 cmd;

/* Disable the CMD_DONE interrupt */
bcm_spi_writeb(bs, 0, SPI_INT_MASK);

dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);

/* Transmitter is inhibited */
bs->tx_ptr = t->tx_buf;
bs->rx_ptr = t->rx_buf;
init_completion(&bs->done);

if (t->tx_buf) {
bs->remaining_bytes = t->len;
bcm63xx_spi_fill_tx_fifo(bs);
}

/* Enable the command done interrupt which
* we use to determine completion of a command */
bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
init_completion(&bs->done);

/* Fill in the Message control register */
msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
Expand All @@ -230,33 +234,76 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
bcm_spi_writew(bs, cmd, SPI_CMD);
wait_for_completion(&bs->done);

/* Disable the CMD_DONE interrupt */
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
/* Enable the CMD_DONE interrupt */
bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);

return t->len - bs->remaining_bytes;
}

static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m)
static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
struct spi_transfer *t;
int ret = 0;
struct bcm63xx_spi *bs = spi_master_get_devdata(master);

if (unlikely(list_empty(&m->transfers)))
return -EINVAL;
pm_runtime_get_sync(&bs->pdev->dev);

if (bs->stopping)
return -ESHUTDOWN;
return 0;
}

static int bcm63xx_spi_unprepare_transfer(struct spi_master *master)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(master);

pm_runtime_put(&bs->pdev->dev);

return 0;
}

static int bcm63xx_spi_transfer_one(struct spi_master *master,
struct spi_message *m)
{
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
struct spi_transfer *t;
struct spi_device *spi = m->spi;
int status = 0;
unsigned int timeout = 0;

list_for_each_entry(t, &m->transfers, transfer_list) {
ret += bcm63xx_txrx_bufs(spi, t);
}
unsigned int len = t->len;
u8 rx_tail;

m->complete(m->context);
status = bcm63xx_spi_check_transfer(spi, t);
if (status < 0)
goto exit;

return ret;
/* configure adapter for a new transfer */
bcm63xx_spi_setup_transfer(spi, t);

while (len) {
/* send the data */
len -= bcm63xx_txrx_bufs(spi, t);

timeout = wait_for_completion_timeout(&bs->done, HZ);
if (!timeout) {
status = -ETIMEDOUT;
goto exit;
}

/* read out all data */
rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);

/* Read out all the data */
if (rx_tail)
memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
}

m->actual_length += t->len;
}
exit:
m->status = status;
spi_finalize_current_message(master);

return 0;
}

/* This driver supports single master mode only. Hence
Expand All @@ -267,39 +314,15 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
struct spi_master *master = (struct spi_master *)dev_id;
struct bcm63xx_spi *bs = spi_master_get_devdata(master);
u8 intr;
u16 cmd;

/* Read interupts and clear them immediately */
intr = bcm_spi_readb(bs, SPI_INT_STATUS);
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
bcm_spi_writeb(bs, 0, SPI_INT_MASK);

/* A tansfer completed */
if (intr & SPI_INTR_CMD_DONE) {
u8 rx_tail;

rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);

/* Read out all the data */
if (rx_tail)
memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);

/* See if there is more data to send */
if (bs->remaining_bytes > 0) {
bcm63xx_spi_fill_tx_fifo(bs);

/* Start the transfer */
bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT,
SPI_MSG_CTL);
cmd = bcm_spi_readw(bs, SPI_CMD);
cmd |= SPI_CMD_START_IMMEDIATE;
cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
bcm_spi_writew(bs, cmd, SPI_CMD);
} else {
complete(&bs->done);
}
}
/* A transfer completed */
if (intr & SPI_INTR_CMD_DONE)
complete(&bs->done);

return IRQ_HANDLED;
}
Expand Down Expand Up @@ -345,7 +368,6 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
}

bs = spi_master_get_devdata(master);
init_completion(&bs->done);

platform_set_drvdata(pdev, master);
bs->pdev = pdev;
Expand Down Expand Up @@ -379,12 +401,13 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect;
master->setup = bcm63xx_spi_setup;
master->transfer = bcm63xx_transfer;
master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
master->transfer_one_message = bcm63xx_spi_transfer_one;
master->mode_bits = MODEBITS;
bs->speed_hz = pdata->speed_hz;
bs->stopping = 0;
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
spin_lock_init(&bs->lock);

/* Initialize hardware */
clk_enable(bs->clk);
Expand Down Expand Up @@ -418,18 +441,16 @@ static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct bcm63xx_spi *bs = spi_master_get_devdata(master);

spi_unregister_master(master);

/* reset spi block */
bcm_spi_writeb(bs, 0, SPI_INT_MASK);
spin_lock(&bs->lock);
bs->stopping = 1;

/* HW shutdown */
clk_disable(bs->clk);
clk_put(bs->clk);

spin_unlock(&bs->lock);
platform_set_drvdata(pdev, 0);
spi_unregister_master(master);

return 0;
}
Expand Down
21 changes: 11 additions & 10 deletions drivers/spi/spi-bfin-sport.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,19 +252,15 @@ static void
bfin_sport_spi_restore_state(struct bfin_sport_spi_master_data *drv_data)
{
struct bfin_sport_spi_slave_data *chip = drv_data->cur_chip;
unsigned int bits = (drv_data->ops == &bfin_sport_transfer_ops_u8 ? 7 : 15);

bfin_sport_spi_disable(drv_data);
dev_dbg(drv_data->dev, "restoring spi ctl state\n");

bfin_write(&drv_data->regs->tcr1, chip->ctl_reg);
bfin_write(&drv_data->regs->tcr2, bits);
bfin_write(&drv_data->regs->tclkdiv, chip->baud);
bfin_write(&drv_data->regs->tfsdiv, bits);
SSYNC();

bfin_write(&drv_data->regs->rcr1, chip->ctl_reg & ~(ITCLK | ITFS));
bfin_write(&drv_data->regs->rcr2, bits);
SSYNC();

bfin_sport_spi_cs_active(chip);
Expand Down Expand Up @@ -420,11 +416,15 @@ bfin_sport_spi_pump_transfers(unsigned long data)
drv_data->cs_change = transfer->cs_change;

/* Bits per word setup */
bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word;
if (bits_per_word == 8)
drv_data->ops = &bfin_sport_transfer_ops_u8;
else
bits_per_word = transfer->bits_per_word ? :
message->spi->bits_per_word ? : 8;
if (bits_per_word % 16 == 0)
drv_data->ops = &bfin_sport_transfer_ops_u16;
else
drv_data->ops = &bfin_sport_transfer_ops_u8;
bfin_write(&drv_data->regs->tcr2, bits_per_word - 1);
bfin_write(&drv_data->regs->tfsdiv, bits_per_word - 1);
bfin_write(&drv_data->regs->rcr2, bits_per_word - 1);

drv_data->state = RUNNING_STATE;

Expand Down Expand Up @@ -598,11 +598,12 @@ bfin_sport_spi_setup(struct spi_device *spi)
}
chip->cs_chg_udelay = chip_info->cs_chg_udelay;
chip->idle_tx_val = chip_info->idle_tx_val;
spi->bits_per_word = chip_info->bits_per_word;
}
}

if (spi->bits_per_word != 8 && spi->bits_per_word != 16) {
if (spi->bits_per_word % 8) {
dev_err(&spi->dev, "%d bits_per_word is not supported\n",
spi->bits_per_word);
ret = -EINVAL;
goto error;
}
Expand Down
Loading

0 comments on commit 84c6a81

Please sign in to comment.