Commit 84c6a81b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'spi-for-linus' of git://git.secretlab.ca/git/linux-2.6

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
parents 9f7e2f90 2431a815
...@@ -74,7 +74,7 @@ config SPI_ATMEL ...@@ -74,7 +74,7 @@ config SPI_ATMEL
This selects a driver for the Atmel SPI Controller, present on This selects a driver for the Atmel SPI Controller, present on
many AT32 (AVR32) and AT91 (ARM) chips. many AT32 (AVR32) and AT91 (ARM) chips.
config SPI_BFIN config SPI_BFIN5XX
tristate "SPI controller driver for ADI Blackfin5xx" tristate "SPI controller driver for ADI Blackfin5xx"
depends on BLACKFIN depends on BLACKFIN
help help
......
...@@ -15,7 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o ...@@ -15,7 +15,7 @@ obj-$(CONFIG_SPI_ATMEL) += spi-atmel.o
obj-$(CONFIG_SPI_ATH79) += spi-ath79.o obj-$(CONFIG_SPI_ATH79) += spi-ath79.o
obj-$(CONFIG_SPI_AU1550) += spi-au1550.o obj-$(CONFIG_SPI_AU1550) += spi-au1550.o
obj-$(CONFIG_SPI_BCM63XX) += spi-bcm63xx.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_BFIN_SPORT) += spi-bfin-sport.o
obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o obj-$(CONFIG_SPI_BITBANG) += spi-bitbang.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o obj-$(CONFIG_SPI_BUTTERFLY) += spi-butterfly.o
......
/* /*
* Broadcom BCM63xx SPI controller support * 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> * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/workqueue.h>
#include <linux/pm_runtime.h>
#include <bcm63xx_dev_spi.h> #include <bcm63xx_dev_spi.h>
...@@ -37,8 +39,6 @@ ...@@ -37,8 +39,6 @@
#define DRV_VER "0.1.2" #define DRV_VER "0.1.2"
struct bcm63xx_spi { struct bcm63xx_spi {
spinlock_t lock;
int stopping;
struct completion done; struct completion done;
void __iomem *regs; void __iomem *regs;
...@@ -96,17 +96,12 @@ static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = { ...@@ -96,17 +96,12 @@ static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
{ 391000, SPI_CLK_0_391MHZ } { 391000, SPI_CLK_0_391MHZ }
}; };
static int bcm63xx_spi_setup_transfer(struct spi_device *spi, static int bcm63xx_spi_check_transfer(struct spi_device *spi,
struct spi_transfer *t) struct spi_transfer *t)
{ {
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
u8 bits_per_word; u8 bits_per_word;
u8 clk_cfg, reg;
u32 hz;
int i;
bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; 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) { if (bits_per_word != 8) {
dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
__func__, bits_per_word); __func__, bits_per_word);
...@@ -119,6 +114,19 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi, ...@@ -119,6 +114,19 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
return -EINVAL; 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 */ /* Find the closest clock configuration */
for (i = 0; i < SPI_CLK_MASK; i++) { for (i = 0; i < SPI_CLK_MASK; i++) {
if (hz <= bcm63xx_spi_freq_table[i][0]) { if (hz <= bcm63xx_spi_freq_table[i][0]) {
...@@ -139,8 +147,6 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi, ...@@ -139,8 +147,6 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
bcm_spi_writeb(bs, reg, SPI_CLK_CFG); bcm_spi_writeb(bs, reg, SPI_CLK_CFG);
dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n", dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n",
clk_cfg, hz); clk_cfg, hz);
return 0;
} }
/* the spi->mode bits understood by this driver: */ /* the spi->mode bits understood by this driver: */
...@@ -153,9 +159,6 @@ static int bcm63xx_spi_setup(struct spi_device *spi) ...@@ -153,9 +159,6 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
bs = spi_master_get_devdata(spi->master); bs = spi_master_get_devdata(spi->master);
if (bs->stopping)
return -ESHUTDOWN;
if (!spi->bits_per_word) if (!spi->bits_per_word)
spi->bits_per_word = 8; spi->bits_per_word = 8;
...@@ -165,7 +168,7 @@ static int bcm63xx_spi_setup(struct spi_device *spi) ...@@ -165,7 +168,7 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
return -EINVAL; return -EINVAL;
} }
ret = bcm63xx_spi_setup_transfer(spi, NULL); ret = bcm63xx_spi_check_transfer(spi, NULL);
if (ret < 0) { if (ret < 0) {
dev_err(&spi->dev, "setup: unsupported mode bits %x\n", dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
spi->mode & ~MODEBITS); spi->mode & ~MODEBITS);
...@@ -190,28 +193,29 @@ static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs) ...@@ -190,28 +193,29 @@ static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
bs->remaining_bytes -= size; 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); struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
u16 msg_ctl; u16 msg_ctl;
u16 cmd; 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", dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len); t->tx_buf, t->rx_buf, t->len);
/* Transmitter is inhibited */ /* Transmitter is inhibited */
bs->tx_ptr = t->tx_buf; bs->tx_ptr = t->tx_buf;
bs->rx_ptr = t->rx_buf; bs->rx_ptr = t->rx_buf;
init_completion(&bs->done);
if (t->tx_buf) { if (t->tx_buf) {
bs->remaining_bytes = t->len; bs->remaining_bytes = t->len;
bcm63xx_spi_fill_tx_fifo(bs); bcm63xx_spi_fill_tx_fifo(bs);
} }
/* Enable the command done interrupt which init_completion(&bs->done);
* we use to determine completion of a command */
bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
/* Fill in the Message control register */ /* Fill in the Message control register */
msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT); msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
...@@ -230,33 +234,76 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) ...@@ -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 |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT); cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
bcm_spi_writew(bs, cmd, SPI_CMD); bcm_spi_writew(bs, cmd, SPI_CMD);
wait_for_completion(&bs->done);
/* Disable the CMD_DONE interrupt */ /* Enable the CMD_DONE interrupt */
bcm_spi_writeb(bs, 0, SPI_INT_MASK); bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
return t->len - bs->remaining_bytes; 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 bcm63xx_spi *bs = spi_master_get_devdata(master);
struct spi_transfer *t;
int ret = 0;
if (unlikely(list_empty(&m->transfers))) pm_runtime_get_sync(&bs->pdev->dev);
return -EINVAL;
if (bs->stopping) return 0;
return -ESHUTDOWN; }
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) { 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 /* This driver supports single master mode only. Hence
...@@ -267,39 +314,15 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id) ...@@ -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 spi_master *master = (struct spi_master *)dev_id;
struct bcm63xx_spi *bs = spi_master_get_devdata(master); struct bcm63xx_spi *bs = spi_master_get_devdata(master);
u8 intr; u8 intr;
u16 cmd;
/* Read interupts and clear them immediately */ /* Read interupts and clear them immediately */
intr = bcm_spi_readb(bs, SPI_INT_STATUS); intr = bcm_spi_readb(bs, SPI_INT_STATUS);
bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
bcm_spi_writeb(bs, 0, SPI_INT_MASK); bcm_spi_writeb(bs, 0, SPI_INT_MASK);
/* A tansfer completed */ /* A transfer completed */
if (intr & SPI_INTR_CMD_DONE) { if (intr & SPI_INTR_CMD_DONE)
u8 rx_tail; complete(&bs->done);
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);
}
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -345,7 +368,6 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev) ...@@ -345,7 +368,6 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
} }
bs = spi_master_get_devdata(master); bs = spi_master_get_devdata(master);
init_completion(&bs->done);
platform_set_drvdata(pdev, master); platform_set_drvdata(pdev, master);
bs->pdev = pdev; bs->pdev = pdev;
...@@ -379,12 +401,13 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev) ...@@ -379,12 +401,13 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
master->bus_num = pdata->bus_num; master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->num_chipselect; master->num_chipselect = pdata->num_chipselect;
master->setup = bcm63xx_spi_setup; 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->speed_hz = pdata->speed_hz;
bs->stopping = 0;
bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA)); bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));
bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA)); bs->rx_io = (const u8 *)(bs->regs + bcm63xx_spireg(SPI_RX_DATA));
spin_lock_init(&bs->lock);
/* Initialize hardware */ /* Initialize hardware */
clk_enable(bs->clk); clk_enable(bs->clk);
...@@ -418,18 +441,16 @@ static int __devexit bcm63xx_spi_remove(struct platform_device *pdev) ...@@ -418,18 +441,16 @@ static int __devexit bcm63xx_spi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev); struct spi_master *master = platform_get_drvdata(pdev);
struct bcm63xx_spi *bs = spi_master_get_devdata(master); struct bcm63xx_spi *bs = spi_master_get_devdata(master);
spi_unregister_master(master);
/* reset spi block */ /* reset spi block */
bcm_spi_writeb(bs, 0, SPI_INT_MASK); bcm_spi_writeb(bs, 0, SPI_INT_MASK);
spin_lock(&bs->lock);
bs->stopping = 1;
/* HW shutdown */ /* HW shutdown */
clk_disable(bs->clk); clk_disable(bs->clk);
clk_put(bs->clk); clk_put(bs->clk);
spin_unlock(&bs->lock);
platform_set_drvdata(pdev, 0); platform_set_drvdata(pdev, 0);
spi_unregister_master(master);
return 0; return 0;
} }
......
...@@ -252,19 +252,15 @@ static void ...@@ -252,19 +252,15 @@ static void
bfin_sport_spi_restore_state(struct bfin_sport_spi_master_data *drv_data) bfin_sport_spi_restore_state(struct bfin_sport_spi_master_data *drv_data)
{ {
struct bfin_sport_spi_slave_data *chip = drv_data->cur_chip; 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); bfin_sport_spi_disable(drv_data);
dev_dbg(drv_data->dev, "restoring spi ctl state\n"); dev_dbg(drv_data->dev, "restoring spi ctl state\n");
bfin_write(&drv_data->regs->tcr1, chip->ctl_reg); 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->tclkdiv, chip->baud);
bfin_write(&drv_data->regs->tfsdiv, bits);
SSYNC(); SSYNC();
bfin_write(&drv_data->regs->rcr1, chip->ctl_reg & ~(ITCLK | ITFS)); bfin_write(&drv_data->regs->rcr1, chip->ctl_reg & ~(ITCLK | ITFS));
bfin_write(&drv_data->regs->rcr2, bits);
SSYNC(); SSYNC();
bfin_sport_spi_cs_active(chip); bfin_sport_spi_cs_active(chip);
...@@ -420,11 +416,15 @@ bfin_sport_spi_pump_transfers(unsigned long data) ...@@ -420,11 +416,15 @@ bfin_sport_spi_pump_transfers(unsigned long data)
drv_data->cs_change = transfer->cs_change; drv_data->cs_change = transfer->cs_change;
/* Bits per word setup */ /* Bits per word setup */
bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word; bits_per_word = transfer->bits_per_word ? :
if (bits_per_word == 8) message->spi->bits_per_word ? : 8;
drv_data->ops = &bfin_sport_transfer_ops_u8; if (bits_per_word % 16 == 0)
else
drv_data->ops = &bfin_sport_transfer_ops_u16; 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; drv_data->state = RUNNING_STATE;
...@@ -598,11 +598,12 @@ bfin_sport_spi_setup(struct spi_device *spi) ...@@ -598,11 +598,12 @@ bfin_sport_spi_setup(struct spi_device *spi)
} }
chip->cs_chg_udelay = chip_info->cs_chg_udelay; chip->cs_chg_udelay = chip_info->cs_chg_udelay;
chip->idle_tx_val = chip_info->idle_tx_val; 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; ret = -EINVAL;
goto error; goto error;
} }
......
...@@ -396,7 +396,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) ...@@ -396,7 +396,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
/* last read */ /* last read */
if (drv_data->rx) { if (drv_data->rx) {
dev_dbg(&drv_data->pdev->dev, "last read\n"); dev_dbg(&drv_data->pdev->dev, "last read\n");
if (n_bytes % 2) { if (!(n_bytes % 2)) {
u16 *buf = (u16 *)drv_data->rx; u16 *buf = (u16 *)drv_data->rx;
for (loop = 0; loop < n_bytes / 2; loop++) for (loop = 0; loop < n_bytes / 2; loop++)
*buf++ = bfin_read(&drv_data->regs->rdbr); *buf++ = bfin_read(&drv_data->regs->rdbr);
...@@ -424,7 +424,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) ...@@ -424,7 +424,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
if (drv_data->rx && drv_data->tx) { if (drv_data->rx && drv_data->tx) {
/* duplex */ /* duplex */
dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n"); dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n");
if (n_bytes % 2) { if (!(n_bytes % 2)) {
u16 *buf = (u16 *)drv_data->rx; u16 *buf = (u16 *)drv_data->rx;
u16 *buf2 = (u16 *)drv_data->tx; u16 *buf2 = (u16 *)drv_data->tx;
for (loop = 0; loop < n_bytes / 2; loop++) { for (loop = 0; loop < n_bytes / 2; loop++) {
...@@ -442,7 +442,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) ...@@ -442,7 +442,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
} else if (drv_data->rx) { } else if (drv_data->rx) {
/* read */ /* read */
dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n"); dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n");
if (n_bytes % 2) { if (!(n_bytes % 2)) {
u16 *buf = (u16 *)drv_data->rx; u16 *buf = (u16 *)drv_data->rx;
for (loop = 0; loop < n_bytes / 2; loop++) { for (loop = 0; loop < n_bytes / 2; loop++) {
*buf++ = bfin_read(&drv_data->regs->rdbr); *buf++ = bfin_read(&drv_data->regs->rdbr);
...@@ -458,7 +458,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id) ...@@ -458,7 +458,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
} else if (drv_data->tx) { } else if (drv_data->tx) {
/* write */ /* write */
dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n"); dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n");
if (n_bytes % 2) { if (!(n_bytes % 2)) {
u16 *buf = (u16 *)drv_data->tx; u16 *buf = (u16 *)drv_data->tx;
for (loop = 0; loop < n_bytes / 2; loop++) { for (loop = 0; loop < n_bytes / 2; loop++) {
bfin_read(&drv_data->regs->rdbr); bfin_read(&drv_data->regs->rdbr);
...@@ -587,6 +587,7 @@ static void bfin_spi_pump_transfers(unsigned long data) ...@@ -587,6 +587,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
if (message->state == DONE_STATE) { if (message->state == DONE_STATE) {
dev_dbg(&drv_data->pdev->dev, "transfer: all done!\n"); dev_dbg(&drv_data->pdev->dev, "transfer: all done!\n");
message->status = 0; message->status = 0;
bfin_spi_flush(drv_data);
bfin_spi_giveback(drv_data); bfin_spi_giveback(drv_data);
return; return;
} }
...@@ -870,8 +871,10 @@ static void bfin_spi_pump_transfers(unsigned long data) ...@@ -870,8 +871,10 @@ static void bfin_spi_pump_transfers(unsigned long data)
message->actual_length += drv_data->len_in_bytes; message->actual_length += drv_data->len_in_bytes;
/* Move to next transfer of this msg */ /* Move to next transfer of this msg */
message->state = bfin_spi_next_transfer(drv_data); message->state = bfin_spi_next_transfer(drv_data);
if (drv_data->cs_change) if (drv_data->cs_change && message->state != DONE_STATE) {
bfin_spi_flush(drv_data);
bfin_spi_cs_deactive(drv_data, chip); bfin_spi_cs_deactive(drv_data, chip);
}
} }
/* Schedule next transfer tasklet */ /* Schedule next transfer tasklet */
...@@ -1026,7 +1029,6 @@ static int bfin_spi_setup(struct spi_device *spi) ...@@ -1026,7 +1029,6 @@ static int bfin_spi_setup(struct spi_device *spi)
chip->cs_chg_udelay = chip_info->cs_chg_udelay; chip->cs_chg_udelay = chip_info->cs_chg_udelay;
chip->idle_tx_val = chip_info->idle_tx_val; chip->idle_tx_val = chip_info->idle_tx_val;
chip->pio_interrupt = chip_info->pio_interrupt; chip->pio_interrupt = chip_info->pio_interrupt;
spi->bits_per_word = chip_info->bits_per_word;
} else { } else {
/* force a default base state */ /* force a default base state */
chip->ctl_reg &= bfin_ctl_reg; chip->ctl_reg &= bfin_ctl_reg;
......
...@@ -545,13 +545,12 @@ static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi) ...@@ -545,13 +545,12 @@ static void ep93xx_spi_pio_transfer(struct ep93xx_spi *espi)
* in case of failure. * in case of failure.
*/ */
static struct dma_async_tx_descriptor * static struct dma_async_tx_descriptor *
ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_transfer_direction dir)
{ {
struct spi_transfer *t = espi->current_msg->state; struct spi_transfer *t = espi->current_msg->state;
struct dma_async_tx_descriptor *txd; struct dma_async_tx_descriptor *txd;
enum dma_slave_buswidth buswidth; enum dma_slave_buswidth buswidth;
struct dma_slave_config conf; struct dma_slave_config conf;
enum dma_transfer_direction slave_dirn;
struct scatterlist *sg; struct scatterlist *sg;
struct sg_table *sgt; struct sg_table *sgt;
struct dma_chan *chan; struct dma_chan *chan;
...@@ -567,14 +566,13 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) ...@@ -567,14 +566,13 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
memset(&conf, 0, sizeof(conf)); memset(&conf, 0, sizeof(conf));
conf.direction = dir; conf.direction = dir;
if (dir == DMA_FROM_DEVICE) { if (dir == DMA_DEV_TO_MEM) {
chan = espi->dma_rx; chan = espi->dma_rx;
buf = t->rx_buf; buf = t->rx_buf;
sgt = &espi->rx_sgt; sgt = &espi->rx_sgt;
conf.src_addr = espi->sspdr_phys; conf.src_addr = espi->sspdr_phys;
conf.src_addr_width = buswidth; conf.src_addr_width = buswidth;
slave_dirn = DMA_DEV_TO_MEM;
} else { } else {
chan = espi->dma_tx; chan = espi->dma_tx;
buf = t->tx_buf; buf = t->tx_buf;
...@@ -582,7 +580,6 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) ...@@ -582,7 +580,6 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
conf.dst_addr = espi->sspdr_phys; conf.dst_addr = espi->sspdr_phys;
conf.dst_addr_width = buswidth; conf.dst_addr_width = buswidth;
slave_dirn = DMA_MEM_TO_DEV;
} }
ret = dmaengine_slave_config(chan, &conf); ret = dmaengine_slave_config(chan, &conf);
...@@ -633,8 +630,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) ...@@ -633,8 +630,7 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
if (!nents) if (!nents)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, txd = dmaengine_prep_slave_sg(chan, sgt->sgl, nents, dir, DMA_CTRL_ACK);
slave_dirn, DMA_CTRL_ACK);
if (!txd) { if (!txd) {
dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir); dma_unmap_sg(chan->device->dev, sgt->sgl, sgt->nents, dir);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -651,12 +647,12 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir) ...@@ -651,12 +647,12 @@ ep93xx_spi_dma_prepare(struct ep93xx_spi *espi, enum dma_data_direction dir)
* unmapped. * unmapped.
*/ */
static void ep93xx_spi_dma_finish(struct ep93xx_spi *espi, static void ep93xx_spi_dma_finish(struct ep93xx_spi *espi,
enum dma_data_direction dir) enum dma_transfer_direction dir)
{ {
struct dma_chan *chan; struct dma_chan *chan;
struct sg_table *sgt; struct sg_table *sgt;
if (dir == DMA_FROM_DEVICE) { if (dir == DMA_DEV_TO_MEM) {
chan = espi->dma_rx; chan = espi->dma_rx;
sgt = &espi->rx_sgt; sgt = &espi->rx_sgt;
} else { } else {
...@@ -677,16 +673,16 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi) ...@@ -677,16 +673,16 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi)
struct spi_message *msg = espi->current_msg; struct spi_message *msg = espi->current_msg;
struct dma_async_tx_descriptor *rxd, *txd; struct dma_async_tx_descriptor *rxd, *txd;
rxd = ep93xx_spi_dma_prepare(espi, DMA_FROM_DEVICE); rxd = ep93xx_spi_dma_prepare(espi, DMA_DEV_TO_MEM);
if (IS_ERR(rxd)) { if (IS_ERR(rxd)) {
dev_err(&espi->pdev->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd)); dev_err(&espi->pdev->dev, "DMA RX failed: %ld\n", PTR_ERR(rxd));
msg->status = PTR_ERR(rxd); msg->status = PTR_ERR(rxd);
return; return;
} }
txd = ep93xx_spi_dma_prepare(espi, DMA_TO_DEVICE); txd = ep93xx_spi_dma_prepare(espi, DMA_MEM_TO_DEV);
if (IS_ERR(txd)) { if (IS_ERR(txd)) {
ep93xx_spi_dma_finish(espi, DMA_FROM_DEVICE); ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM);
dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(rxd)); dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(rxd));
msg->status = PTR_ERR(txd); msg->status = PTR_ERR(txd);
return; return;
...@@ -705,8 +701,8 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi) ...@@ -705,8 +701,8 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi)
wait_for_completion(&espi->wait); wait_for_completion(&espi->wait);
ep93xx_spi_dma_finish(espi, DMA_TO_DEVICE); ep93xx_spi_dma_finish(espi, DMA_MEM_TO_DEV);
ep93xx_spi_dma_finish(espi, DMA_FROM_DEVICE); ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM);
} }
/** /**
......
...@@ -1667,9 +1667,15 @@ static int calculate_effective_freq(struct pl022 *pl022, int freq, struct ...@@ -1667,9 +1667,15 @@ static int calculate_effective_freq(struct pl022 *pl022, int freq, struct
/* cpsdvsr = 254 & scr = 255 */ /* cpsdvsr = 254 & scr = 255 */
min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX); min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX);
if (!((freq <= max_tclk) && (freq >= min_tclk))) { if (freq > max_tclk)
dev_warn(&pl022->adev->dev,
"Max speed that can be programmed is %d Hz, you requested %d\n",
max_tclk, freq);
if (freq < min_tclk) {
dev_err(&pl022->adev->dev, dev_err(&pl022->adev->dev,
"controller data is incorrect: out of range frequency"); "Requested frequency: %d Hz is less than minimum possible %d Hz\n",
freq, min_tclk);
return -EINVAL; return -EINVAL;
} }
...@@ -1681,26 +1687,37 @@ static int calculate_effective_freq(struct pl022 *pl022, int freq, struct ...@@ -1681,26 +1687,37 @@ static int calculate_effective_freq(struct pl022 *pl022, int freq, struct
while (scr <= SCR_MAX) { while (scr <= SCR_MAX) {
tmp = spi_rate(rate, cpsdvsr, scr); tmp = spi_rate(rate, cpsdvsr, scr);
if (tmp > freq) if (tmp > freq) {
/* we need lower freq */
scr++; scr++;
continue;
}
/* /*
* If found exact value, update and break. * If found exact value, mark found and break.
* If found more closer value, update and continue. * If found more closer value, update and break.
*/ */
else if ((tmp == freq) || (tmp > best_freq)) { if (tmp > best_freq) {
best_freq = tmp; best_freq = tmp;
best_cpsdvsr = cpsdvsr; best_cpsdvsr = cpsdvsr;
best_scr = scr; best_scr = scr;
if (tmp == freq) if (tmp == freq)
break; found = 1;
} }
scr++; /*
* increased scr will give lower rates, which are not
* required
*/
break;
} }
cpsdvsr += 2; cpsdvsr += 2;
scr = SCR_MIN; scr = SCR_MIN;
} }
WARN(!best_freq, "pl022: Matching cpsdvsr and scr not found for %d Hz rate \n",
freq);
clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF); clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF);
clk_freq->scr = (u8) (best_scr & 0xFF); clk_freq->scr = (u8) (best_scr & 0xFF);
dev_dbg(&pl022->adev->dev, dev_dbg(&pl022->adev->dev,
...@@ -1823,9 +1840,12 @@ static int pl022_setup(struct spi_device *spi) ...@@ -1823,9 +1840,12 @@ static int pl022_setup(struct spi_device *spi)
} else } else
chip->cs_control = chip_info->cs_control; chip->cs_control = chip_info->cs_control;
if (bits <= 3) { /* Check bits per word with vendor specific range */
/* PL022 doesn't support less than 4-bits */ if ((bits <= 3) || (bits > pl022->vendor->max_bpw)) {
status = -ENOTSUPP; status = -ENOTSUPP;
dev_err(&spi->dev, "illegal data size for this controller!\n");
dev_err(&spi->dev, "This controller can only handle 4 <= n <= %d bit words\n",
pl022->vendor->max_bpw);
goto err_config_params; goto err_config_params;
} else if (bits <= 8) { } else if (bits <= 8) {
dev_dbg(&spi->dev, "4 <= n <=8 bits per word\n"); dev_dbg(&spi->dev, "4 <= n <=8 bits per word\n");
...@@ -1838,20 +1858,10 @@ static int pl022_setup(struct spi_device *spi) ...@@ -1838,20 +1858,10 @@ static int pl022_setup(struct spi_device *spi)
chip->read = READING_U16; chip->read = READING_U16;
chip->write = WRITING_U16; chip->write = WRITING_U16;
} else { } else {
if (pl022->vendor->max_bpw >= 32) { dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n");
dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n"); chip->n_bytes = 4;
chip->n_bytes = 4; chip->read = READING_U32;
chip->read = READING_U32; chip->write = WRITING_U32;
chip->write = WRITING_U32;
} else {
dev_err(&spi->dev,
"illegal data size for this controller!\n");
dev_err(&spi->dev,
"a standard pl022 can only handle "
"1 <= n <= 16 bit words\n");
status = -ENOTSUPP;
goto err_config_params;
}
} }
/* Now Initialize all register settings required for this chip */ /* Now Initialize all register settings required for this chip */
......
...@@ -254,7 +254,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) ...@@ -254,7 +254,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* driver is finished with this message, it must call * driver is finished with this message, it must call
* spi_finalize_current_message() so the subsystem can issue the next * spi_finalize_current_message() so the subsystem can issue the next
* transfer * transfer
* @prepare_transfer_hardware: there are currently no more messages on the * @unprepare_transfer_hardware: there are currently no more messages on the
* queue so the subsystem notifies the driver that it may relax the * queue so the subsystem notifies the driver that it may relax the
* hardware by issuing this call * hardware by issuing this call
* *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment