summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/amba-pl022.c71
-rw-r--r--drivers/spi/spi_bfin5xx.c104
-rw-r--r--drivers/spi/spi_bitbang.c13
-rw-r--r--drivers/spi/spi_imx.c12
-rw-r--r--drivers/spi/spi_sh_msiof.c127
-rw-r--r--drivers/spi/spidev.c12
6 files changed, 229 insertions, 110 deletions
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index 71a1219a995d..4cd05cc05a55 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -329,15 +329,16 @@ struct vendor_data {
/**
* struct pl022 - This is the private SSP driver data structure
* @adev: AMBA device model hookup
- * @vendor: Vendor data for the IP block
- * @phybase: The physical memory where the SSP device resides
- * @virtbase: The virtual memory where the SSP is mapped
+ * @vendor: vendor data for the IP block
+ * @phybase: the physical memory where the SSP device resides
+ * @virtbase: the virtual memory where the SSP is mapped
+ * @clk: outgoing clock "SPICLK" for the SPI bus
* @master: SPI framework hookup
* @master_info: controller-specific data from machine setup
- * @regs: SSP controller register's virtual address
- * @pump_messages: Work struct for scheduling work to the workqueue
- * @lock: spinlock to syncronise access to driver data
* @workqueue: a workqueue on which any spi_message request is queued
+ * @pump_messages: work struct for scheduling work to the workqueue
+ * @queue_lock: spinlock to syncronise access to message queue
+ * @queue: message queue
* @busy: workqueue is busy
* @running: workqueue is running
* @pump_transfers: Tasklet used in Interrupt Transfer mode
@@ -348,8 +349,14 @@ struct vendor_data {
* @tx_end: end position in TX buffer to be read
* @rx: current position in RX buffer to be written
* @rx_end: end position in RX buffer to be written
- * @readingtype: the type of read currently going on
- * @writingtype: the type or write currently going on
+ * @read: the type of read currently going on
+ * @write: the type of write currently going on
+ * @exp_fifo_level: expected FIFO level
+ * @dma_rx_channel: optional channel for RX DMA
+ * @dma_tx_channel: optional channel for TX DMA
+ * @sgt_rx: scattertable for the RX transfer
+ * @sgt_tx: scattertable for the TX transfer
+ * @dummypage: a dummy page used for driving data on the bus with DMA
*/
struct pl022 {
struct amba_device *adev;
@@ -397,8 +404,8 @@ struct pl022 {
* @cpsr: Value of Clock prescale register
* @n_bytes: how many bytes(power of 2) reqd for a given data width of client
* @enable_dma: Whether to enable DMA or not
- * @write: function ptr to be used to write when doing xfer for this chip
* @read: function ptr to be used to read when doing xfer for this chip
+ * @write: function ptr to be used to write when doing xfer for this chip
* @cs_control: chip select callback provided by chip
* @xfer_type: polling/interrupt/DMA
*
@@ -508,9 +515,10 @@ static void giveback(struct pl022 *pl022)
msg->state = NULL;
if (msg->complete)
msg->complete(msg->context);
- /* This message is completed, so let's turn off the clocks! */
+ /* This message is completed, so let's turn off the clocks & power */
clk_disable(pl022->clk);
amba_pclk_disable(pl022->adev);
+ amba_vcore_disable(pl022->adev);
}
/**
@@ -917,7 +925,6 @@ static int configure_dma(struct pl022 *pl022)
struct dma_chan *txchan = pl022->dma_tx_channel;
struct dma_async_tx_descriptor *rxdesc;
struct dma_async_tx_descriptor *txdesc;
- dma_cookie_t cookie;
/* Check that the channels are available */
if (!rxchan || !txchan)
@@ -962,10 +969,8 @@ static int configure_dma(struct pl022 *pl022)
tx_conf.dst_addr_width = rx_conf.src_addr_width;
BUG_ON(rx_conf.src_addr_width != tx_conf.dst_addr_width);
- rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
- (unsigned long) &rx_conf);
- txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
- (unsigned long) &tx_conf);
+ dmaengine_slave_config(rxchan, &rx_conf);
+ dmaengine_slave_config(txchan, &tx_conf);
/* Create sglists for the transfers */
pages = (pl022->cur_transfer->len >> PAGE_SHIFT) + 1;
@@ -1018,23 +1023,19 @@ static int configure_dma(struct pl022 *pl022)
rxdesc->callback_param = pl022;
/* Submit and fire RX and TX with TX last so we're ready to read! */
- cookie = rxdesc->tx_submit(rxdesc);
- if (dma_submit_error(cookie))
- goto err_submit_rx;
- cookie = txdesc->tx_submit(txdesc);
- if (dma_submit_error(cookie))
- goto err_submit_tx;
- rxchan->device->device_issue_pending(rxchan);
- txchan->device->device_issue_pending(txchan);
+ dmaengine_submit(rxdesc);
+ dmaengine_submit(txdesc);
+ dma_async_issue_pending(rxchan);
+ dma_async_issue_pending(txchan);
return 0;
err_submit_tx:
err_submit_rx:
err_txdesc:
- txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(txchan);
err_rxdesc:
- rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(rxchan);
dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl,
pl022->sgt_tx.nents, DMA_TO_DEVICE);
err_tx_sgmap:
@@ -1101,8 +1102,8 @@ static void terminate_dma(struct pl022 *pl022)
struct dma_chan *rxchan = pl022->dma_rx_channel;
struct dma_chan *txchan = pl022->dma_tx_channel;
- rxchan->device->device_control(rxchan, DMA_TERMINATE_ALL, 0);
- txchan->device->device_control(txchan, DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(rxchan);
+ dmaengine_terminate_all(txchan);
unmap_free_dma_scatter(pl022);
}
@@ -1482,9 +1483,11 @@ static void pump_messages(struct work_struct *work)
/* Setup the SPI using the per chip configuration */
pl022->cur_chip = spi_get_ctldata(pl022->cur_msg->spi);
/*
- * We enable the clocks here, then the clocks will be disabled when
- * giveback() is called in each method (poll/interrupt/DMA)
+ * We enable the core voltage and clocks here, then the clocks
+ * and core will be disabled when giveback() is called in each method
+ * (poll/interrupt/DMA)
*/
+ amba_vcore_enable(pl022->adev);
amba_pclk_enable(pl022->adev);
clk_enable(pl022->clk);
restore_state(pl022);
@@ -1910,8 +1913,6 @@ static int pl022_setup(struct spi_device *spi)
&& ((pl022->master_info)->enable_dma)) {
chip->enable_dma = true;
dev_dbg(&spi->dev, "DMA mode set in controller state\n");
- if (status < 0)
- goto err_config_params;
SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
SSP_DMACR_MASK_RXDMAE, 0);
SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED,
@@ -2130,8 +2131,12 @@ pl022_probe(struct amba_device *adev, struct amba_id *id)
goto err_spi_register;
}
dev_dbg(dev, "probe succeded\n");
- /* Disable the silicon block pclk and clock it when needed */
+ /*
+ * Disable the silicon block pclk and any voltage domain and just
+ * power it up and clock it when it's needed
+ */
amba_pclk_disable(adev);
+ amba_vcore_disable(adev);
return 0;
err_spi_register:
@@ -2196,9 +2201,11 @@ static int pl022_suspend(struct amba_device *adev, pm_message_t state)
return status;
}
+ amba_vcore_enable(adev);
amba_pclk_enable(adev);
load_ssp_default_config(pl022);
amba_pclk_disable(adev);
+ amba_vcore_disable(adev);
dev_dbg(&adev->dev, "suspended\n");
return 0;
}
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index 3f223511127b..a28462486df8 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -425,6 +425,7 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
struct bfin_spi_slave_data *chip = drv_data->cur_chip;
struct spi_message *msg = drv_data->cur_msg;
int n_bytes = drv_data->n_bytes;
+ int loop = 0;
/* wait until transfer finished. */
while (!(read_STAT(drv_data) & BIT_STAT_RXS))
@@ -435,10 +436,15 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
/* last read */
if (drv_data->rx) {
dev_dbg(&drv_data->pdev->dev, "last read\n");
- if (n_bytes == 2)
- *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
- else if (n_bytes == 1)
- *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
+ if (n_bytes % 2) {
+ u16 *buf = (u16 *)drv_data->rx;
+ for (loop = 0; loop < n_bytes / 2; loop++)
+ *buf++ = read_RDBR(drv_data);
+ } else {
+ u8 *buf = (u8 *)drv_data->rx;
+ for (loop = 0; loop < n_bytes; loop++)
+ *buf++ = read_RDBR(drv_data);
+ }
drv_data->rx += n_bytes;
}
@@ -458,29 +464,53 @@ static irqreturn_t bfin_spi_pio_irq_handler(int irq, void *dev_id)
if (drv_data->rx && drv_data->tx) {
/* duplex */
dev_dbg(&drv_data->pdev->dev, "duplex: write_TDBR\n");
- if (drv_data->n_bytes == 2) {
- *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
- write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
- } else if (drv_data->n_bytes == 1) {
- *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
- write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ if (n_bytes % 2) {
+ 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++);
+ }
+ } 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++);
+ }
}
} else if (drv_data->rx) {
/* read */
dev_dbg(&drv_data->pdev->dev, "read: write_TDBR\n");
- if (drv_data->n_bytes == 2)
- *(u16 *) (drv_data->rx) = read_RDBR(drv_data);
- else if (drv_data->n_bytes == 1)
- *(u8 *) (drv_data->rx) = read_RDBR(drv_data);
- write_TDBR(drv_data, chip->idle_tx_val);
+ 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);
+ }
+ } 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);
+ }
+ }
} else if (drv_data->tx) {
/* write */
dev_dbg(&drv_data->pdev->dev, "write: write_TDBR\n");
- bfin_spi_dummy_read(drv_data);
- if (drv_data->n_bytes == 2)
- write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
- else if (drv_data->n_bytes == 1)
- write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
+ 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++);
+ }
+ } else {
+ u8 *buf = (u8 *)drv_data->tx;
+ for (loop = 0; loop < n_bytes; loop++) {
+ read_RDBR(drv_data);
+ write_TDBR(drv_data, *buf++);
+ }
+ }
}
if (drv_data->tx)
@@ -623,6 +653,7 @@ static void bfin_spi_pump_transfers(unsigned long data)
message->state = bfin_spi_next_transfer(drv_data);
/* Schedule next transfer tasklet */
tasklet_schedule(&drv_data->pump_transfers);
+ return;
}
if (transfer->tx_buf != NULL) {
@@ -651,16 +682,16 @@ static void bfin_spi_pump_transfers(unsigned long data)
/* Bits per word setup */
bits_per_word = transfer->bits_per_word ? : message->spi->bits_per_word;
- if (bits_per_word == 8) {
- drv_data->n_bytes = 1;
- drv_data->len = transfer->len;
- cr_width = 0;
- drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
- } else if (bits_per_word == 16) {
- drv_data->n_bytes = 2;
+ if ((bits_per_word > 0) && (bits_per_word % 16 == 0)) {
+ drv_data->n_bytes = bits_per_word/8;
drv_data->len = (transfer->len) >> 1;
cr_width = BIT_CTL_WORDSIZE;
drv_data->ops = &bfin_bfin_spi_transfer_ops_u16;
+ } else if ((bits_per_word > 0) && (bits_per_word % 8 == 0)) {
+ drv_data->n_bytes = bits_per_word/8;
+ drv_data->len = transfer->len;
+ cr_width = 0;
+ drv_data->ops = &bfin_bfin_spi_transfer_ops_u8;
} else {
dev_err(&drv_data->pdev->dev, "transfer: unsupported bits_per_word\n");
message->status = -EINVAL;
@@ -815,10 +846,19 @@ static void bfin_spi_pump_transfers(unsigned long data)
if (drv_data->tx == NULL)
write_TDBR(drv_data, chip->idle_tx_val);
else {
- if (bits_per_word == 8)
- write_TDBR(drv_data, (*(u8 *) (drv_data->tx)));
- else
- write_TDBR(drv_data, (*(u16 *) (drv_data->tx)));
+ 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++);
+ }
+ } 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++);
+ }
+
drv_data->tx += drv_data->n_bytes;
}
@@ -1031,7 +1071,7 @@ static int bfin_spi_setup(struct spi_device *spi)
chip->ctl_reg &= bfin_ctl_reg;
}
- 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);
goto error;
diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c
index 8b55724d5f39..14a63f6010d1 100644
--- a/drivers/spi/spi_bitbang.c
+++ b/drivers/spi/spi_bitbang.c
@@ -259,10 +259,6 @@ static void bitbang_work(struct work_struct *work)
struct spi_bitbang *bitbang =
container_of(work, struct spi_bitbang, work);
unsigned long flags;
- int (*setup_transfer)(struct spi_device *,
- struct spi_transfer *);
-
- setup_transfer = bitbang->setup_transfer;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;
@@ -300,11 +296,7 @@ static void bitbang_work(struct work_struct *work)
/* init (-1) or override (1) transfer params */
if (do_setup != 0) {
- if (!setup_transfer) {
- status = -ENOPROTOOPT;
- break;
- }
- status = setup_transfer(spi, t);
+ status = bitbang->setup_transfer(spi, t);
if (status < 0)
break;
if (do_setup == -1)
@@ -465,6 +457,9 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
}
} else if (!bitbang->master->setup)
return -EINVAL;
+ if (bitbang->master->transfer == spi_bitbang_transfer &&
+ !bitbang->setup_transfer)
+ return -EINVAL;
/* this task is the only thing to touch the SPI bits */
bitbang->busy = 0;
diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c
index 1cf9d5faabf4..69d6dba67c19 100644
--- a/drivers/spi/spi_imx.c
+++ b/drivers/spi/spi_imx.c
@@ -174,7 +174,7 @@ static unsigned int spi_imx_clkdiv_2(unsigned int fin,
#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(cs) (1 << ((cs) + 4))
+#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)
@@ -253,8 +253,14 @@ static int __maybe_unused spi_imx2_3_config(struct spi_imx_data *spi_imx,
{
u32 ctrl = SPI_IMX2_3_CTRL_ENABLE, cfg = 0;
- /* set master mode */
- ctrl |= SPI_IMX2_3_CTRL_MODE(config->cs);
+ /*
+ * The hardware seems to have a race condition when changing modes. The
+ * current assumption is that the selection of the channel arrives
+ * earlier in the hardware than the mode bits when they are written at
+ * the same time.
+ * So set master mode for all channels as we do not support slave mode.
+ */
+ ctrl |= SPI_IMX2_3_CTRL_MODE_MASK;
/* set clock speed */
ctrl |= spi_imx2_3_clkdiv(spi_imx->spi_clk, config->speed_hz);
diff --git a/drivers/spi/spi_sh_msiof.c b/drivers/spi/spi_sh_msiof.c
index 56f60c8ea0ab..da6e42ec856e 100644
--- a/drivers/spi/spi_sh_msiof.c
+++ b/drivers/spi/spi_sh_msiof.c
@@ -9,22 +9,22 @@
*
*/
-#include <linux/kernel.h>
-#include <linux/init.h>
+#include <linux/bitmap.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/platform_device.h>
-#include <linux/completion.h>
#include <linux/pm_runtime.h>
-#include <linux/gpio.h>
-#include <linux/bitmap.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/err.h>
+#include <linux/spi/sh_msiof.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi_bitbang.h>
-#include <linux/spi/sh_msiof.h>
#include <asm/unaligned.h>
@@ -67,7 +67,7 @@ struct sh_msiof_spi_priv {
#define STR_TEOF (1 << 23)
#define STR_REOF (1 << 7)
-static unsigned long sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
+static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
{
switch (reg_offs) {
case TSCR:
@@ -79,7 +79,7 @@ static unsigned long sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs)
}
static void sh_msiof_write(struct sh_msiof_spi_priv *p, int reg_offs,
- unsigned long value)
+ u32 value)
{
switch (reg_offs) {
case TSCR:
@@ -93,10 +93,10 @@ static void sh_msiof_write(struct sh_msiof_spi_priv *p, int reg_offs,
}
static int sh_msiof_modify_ctr_wait(struct sh_msiof_spi_priv *p,
- unsigned long clr, unsigned long set)
+ u32 clr, u32 set)
{
- unsigned long mask = clr | set;
- unsigned long data;
+ u32 mask = clr | set;
+ u32 data;
int k;
data = sh_msiof_read(p, CTR);
@@ -166,10 +166,10 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
}
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
- int cpol, int cpha,
- int tx_hi_z, int lsb_first)
+ u32 cpol, u32 cpha,
+ u32 tx_hi_z, u32 lsb_first)
{
- unsigned long tmp;
+ u32 tmp;
int edge;
/*
@@ -187,7 +187,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
tmp |= cpol << 30; /* TSCKIZ */
tmp |= cpol << 28; /* RSCKIZ */
- edge = cpol ? cpha : !cpha;
+ edge = cpol ^ !cpha;
tmp |= edge << 27; /* TEDG */
tmp |= edge << 26; /* REDG */
@@ -197,11 +197,9 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p,
const void *tx_buf, void *rx_buf,
- int bits, int words)
+ u32 bits, u32 words)
{
- unsigned long dr2;
-
- dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
+ u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16);
if (tx_buf)
sh_msiof_write(p, TMDR2, dr2);
@@ -222,7 +220,7 @@ static void sh_msiof_reset_str(struct sh_msiof_spi_priv *p)
static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
const void *tx_buf, int words, int fs)
{
- const unsigned char *buf_8 = tx_buf;
+ const u8 *buf_8 = tx_buf;
int k;
for (k = 0; k < words; k++)
@@ -232,7 +230,7 @@ static void sh_msiof_spi_write_fifo_8(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_write_fifo_16(struct sh_msiof_spi_priv *p,
const void *tx_buf, int words, int fs)
{
- const unsigned short *buf_16 = tx_buf;
+ const u16 *buf_16 = tx_buf;
int k;
for (k = 0; k < words; k++)
@@ -242,7 +240,7 @@ static void sh_msiof_spi_write_fifo_16(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_write_fifo_16u(struct sh_msiof_spi_priv *p,
const void *tx_buf, int words, int fs)
{
- const unsigned short *buf_16 = tx_buf;
+ const u16 *buf_16 = tx_buf;
int k;
for (k = 0; k < words; k++)
@@ -252,7 +250,7 @@ static void sh_msiof_spi_write_fifo_16u(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_write_fifo_32(struct sh_msiof_spi_priv *p,
const void *tx_buf, int words, int fs)
{
- const unsigned int *buf_32 = tx_buf;
+ const u32 *buf_32 = tx_buf;
int k;
for (k = 0; k < words; k++)
@@ -262,17 +260,37 @@ static void sh_msiof_spi_write_fifo_32(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_write_fifo_32u(struct sh_msiof_spi_priv *p,
const void *tx_buf, int words, int fs)
{
- const unsigned int *buf_32 = tx_buf;
+ const u32 *buf_32 = tx_buf;
int k;
for (k = 0; k < words; k++)
sh_msiof_write(p, TFDR, get_unaligned(&buf_32[k]) << fs);
}
+static void sh_msiof_spi_write_fifo_s32(struct sh_msiof_spi_priv *p,
+ const void *tx_buf, int words, int fs)
+{
+ const u32 *buf_32 = tx_buf;
+ int k;
+
+ for (k = 0; k < words; k++)
+ sh_msiof_write(p, TFDR, swab32(buf_32[k] << fs));
+}
+
+static void sh_msiof_spi_write_fifo_s32u(struct sh_msiof_spi_priv *p,
+ const void *tx_buf, int words, int fs)
+{
+ const u32 *buf_32 = tx_buf;
+ int k;
+
+ for (k = 0; k < words; k++)
+ sh_msiof_write(p, TFDR, swab32(get_unaligned(&buf_32[k]) << fs));
+}
+
static void sh_msiof_spi_read_fifo_8(struct sh_msiof_spi_priv *p,
void *rx_buf, int words, int fs)
{
- unsigned char *buf_8 = rx_buf;
+ u8 *buf_8 = rx_buf;
int k;
for (k = 0; k < words; k++)
@@ -282,7 +300,7 @@ static void sh_msiof_spi_read_fifo_8(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_read_fifo_16(struct sh_msiof_spi_priv *p,
void *rx_buf, int words, int fs)
{
- unsigned short *buf_16 = rx_buf;
+ u16 *buf_16 = rx_buf;
int k;
for (k = 0; k < words; k++)
@@ -292,7 +310,7 @@ static void sh_msiof_spi_read_fifo_16(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_read_fifo_16u(struct sh_msiof_spi_priv *p,
void *rx_buf, int words, int fs)
{
- unsigned short *buf_16 = rx_buf;
+ u16 *buf_16 = rx_buf;
int k;
for (k = 0; k < words; k++)
@@ -302,7 +320,7 @@ static void sh_msiof_spi_read_fifo_16u(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_read_fifo_32(struct sh_msiof_spi_priv *p,
void *rx_buf, int words, int fs)
{
- unsigned int *buf_32 = rx_buf;
+ u32 *buf_32 = rx_buf;
int k;
for (k = 0; k < words; k++)
@@ -312,19 +330,40 @@ static void sh_msiof_spi_read_fifo_32(struct sh_msiof_spi_priv *p,
static void sh_msiof_spi_read_fifo_32u(struct sh_msiof_spi_priv *p,
void *rx_buf, int words, int fs)
{
- unsigned int *buf_32 = rx_buf;
+ u32 *buf_32 = rx_buf;
int k;
for (k = 0; k < words; k++)
put_unaligned(sh_msiof_read(p, RFDR) >> fs, &buf_32[k]);
}
+static void sh_msiof_spi_read_fifo_s32(struct sh_msiof_spi_priv *p,
+ void *rx_buf, int words, int fs)
+{
+ u32 *buf_32 = rx_buf;
+ int k;
+
+ for (k = 0; k < words; k++)
+ buf_32[k] = swab32(sh_msiof_read(p, RFDR) >> fs);
+}
+
+static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p,
+ void *rx_buf, int words, int fs)
+{
+ u32 *buf_32 = rx_buf;
+ int k;
+
+ for (k = 0; k < words; k++)
+ put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]);
+}
+
static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t)
{
int bits;
bits = t ? t->bits_per_word : 0;
- bits = bits ? bits : spi->bits_per_word;
+ if (!bits)
+ bits = spi->bits_per_word;
return bits;
}
@@ -334,7 +373,8 @@ static unsigned long sh_msiof_spi_hz(struct spi_device *spi,
unsigned long hz;
hz = t ? t->speed_hz : 0;
- hz = hz ? hz : spi->max_speed_hz;
+ if (!hz)
+ hz = spi->max_speed_hz;
return hz;
}
@@ -468,9 +508,17 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
int bytes_done;
int words;
int n;
+ bool swab;
bits = sh_msiof_spi_bits(spi, t);
+ if (bits <= 8 && t->len > 15 && !(t->len & 3)) {
+ bits = 32;
+ swab = true;
+ } else {
+ swab = false;
+ }
+
/* setup bytes per word and fifo read/write functions */
if (bits <= 8) {
bytes_per_word = 1;
@@ -487,6 +535,17 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
rx_fifo = sh_msiof_spi_read_fifo_16u;
else
rx_fifo = sh_msiof_spi_read_fifo_16;
+ } else if (swab) {
+ bytes_per_word = 4;
+ if ((unsigned long)t->tx_buf & 0x03)
+ tx_fifo = sh_msiof_spi_write_fifo_s32u;
+ else
+ tx_fifo = sh_msiof_spi_write_fifo_s32;
+
+ if ((unsigned long)t->rx_buf & 0x03)
+ rx_fifo = sh_msiof_spi_read_fifo_s32u;
+ else
+ rx_fifo = sh_msiof_spi_read_fifo_s32;
} else {
bytes_per_word = 4;
if ((unsigned long)t->tx_buf & 0x03)
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 603428213d21..d9fd86211365 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -30,6 +30,7 @@
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/compat.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
@@ -471,6 +472,16 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return retval;
}
+#ifdef CONFIG_COMPAT
+static long
+spidev_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ return spidev_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define spidev_compat_ioctl NULL
+#endif /* CONFIG_COMPAT */
+
static int spidev_open(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
@@ -543,6 +554,7 @@ static const struct file_operations spidev_fops = {
.write = spidev_write,
.read = spidev_read,
.unlocked_ioctl = spidev_ioctl,
+ .compat_ioctl = spidev_compat_ioctl,
.open = spidev_open,
.release = spidev_release,
.llseek = no_llseek,