aboutsummaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/atmel_spi.c29
-rw-r--r--drivers/spi/spi_bfin5xx.c7
-rw-r--r--drivers/spi/spi_s3c24xx.c6
3 files changed, 28 insertions, 14 deletions
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 02c8e305b14f..e81d59d78910 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -497,7 +497,7 @@ static int atmel_spi_setup(struct spi_device *spi)
struct atmel_spi *as;
u32 scbr, csr;
unsigned int bits = spi->bits_per_word;
- unsigned long bus_hz, sck_hz;
+ unsigned long bus_hz;
unsigned int npcs_pin;
int ret;
@@ -536,14 +536,25 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
- /* speed zero convention is used by some upper layers */
+ /*
+ * Pre-new_1 chips start out at half the peripheral
+ * bus speed.
+ */
bus_hz = clk_get_rate(as->clk);
+ if (!as->new_1)
+ bus_hz /= 2;
+
if (spi->max_speed_hz) {
- /* assume div32/fdiv/mbz == 0 */
- if (!as->new_1)
- bus_hz /= 2;
- scbr = ((bus_hz + spi->max_speed_hz - 1)
- / spi->max_speed_hz);
+ /*
+ * Calculate the lowest divider that satisfies the
+ * constraint, assuming div32/fdiv/mbz == 0.
+ */
+ scbr = DIV_ROUND_UP(bus_hz, spi->max_speed_hz);
+
+ /*
+ * If the resulting divider doesn't fit into the
+ * register bitfield, we can't satisfy the constraint.
+ */
if (scbr >= (1 << SPI_SCBR_SIZE)) {
dev_dbg(&spi->dev,
"setup: %d Hz too slow, scbr %u; min %ld Hz\n",
@@ -551,8 +562,8 @@ static int atmel_spi_setup(struct spi_device *spi)
return -EINVAL;
}
} else
+ /* speed zero means "as slow as possible" */
scbr = 0xff;
- sck_hz = bus_hz / scbr;
csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8);
if (spi->mode & SPI_CPOL)
@@ -589,7 +600,7 @@ static int atmel_spi_setup(struct spi_device *spi)
dev_dbg(&spi->dev,
"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
- sck_hz, bits, spi->mode, spi->chip_select, csr);
+ bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index a9ac1fdb3094..7fea3cf4588a 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -608,6 +608,7 @@ static void pump_transfers(unsigned long data)
u8 width;
u16 cr, dma_width, dma_config;
u32 tranf_success = 1;
+ u8 full_duplex = 0;
/* Get current state information */
message = drv_data->cur_msg;
@@ -658,6 +659,7 @@ static void pump_transfers(unsigned long data)
}
if (transfer->rx_buf != NULL) {
+ full_duplex = transfer->tx_buf != NULL;
drv_data->rx = transfer->rx_buf;
drv_data->rx_end = drv_data->rx + transfer->len;
dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
@@ -740,7 +742,8 @@ static void pump_transfers(unsigned long data)
* successful use different way to r/w according to
* drv_data->cur_chip->enable_dma
*/
- if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
+ if (!full_duplex && drv_data->cur_chip->enable_dma
+ && drv_data->len > 6) {
disable_dma(drv_data->dma_channel);
clear_dma_irqstat(drv_data->dma_channel);
@@ -828,7 +831,7 @@ static void pump_transfers(unsigned long data)
/* IO mode write then read */
dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
- if (drv_data->tx != NULL && drv_data->rx != NULL) {
+ if (full_duplex) {
/* full duplex mode */
BUG_ON((drv_data->tx_end - drv_data->tx) !=
(drv_data->rx_end - drv_data->rx));
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 34bfb7dd7764..0885cc357a37 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -125,10 +125,10 @@ static int s3c24xx_spi_setupxfer(struct spi_device *spi,
/* is clk = pclk / (2 * (pre+1)), or is it
* clk = (pclk * 2) / ( pre + 1) */
- div = (div / 2) - 1;
+ div /= 2;
- if (div < 0)
- div = 1;
+ if (div > 0)
+ div -= 1;
if (div > 255)
div = 255;