mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
Merge branch 'spi/next' of git://git.secretlab.ca/git/linux-2.6
* 'spi/next' of git://git.secretlab.ca/git/linux-2.6: spi/amba-pl022: work in polling or interrupt mode if pl022_dma_probe fails spi/spi_s3c24xx: Use spi_bitbang_stop instead of spi_unregister_master in s3c24xx_spi_remove spi/spi_nuc900: Use spi_bitbang_stop instead of spi_unregister_master in nuc900_spi_remove spi/spi_tegra: use spi_unregister_master() instead of spi_master_put() spi/spi_sh: use spi_unregister_master instead of spi_master_put in remove path spi: Use void pointers for data in simple SPI I/O operations spi/pl022: use cpu_relax in the busy loop spi/pl022: mark driver non-experimental spi/pl022: timeout on polled transfer v2 spi/dw_spi: improve the interrupt mode with the batch ops spi/dw_spi: change poll mode transfer from byte ops to batch ops spi/dw_spi: remove the un-necessary flush() spi/dw_spi: unify the low level read/write routines
This commit is contained in:
commit
20e0ec119b
10 changed files with 111 additions and 174 deletions
|
@ -271,8 +271,8 @@ config SPI_ORION
|
||||||
This enables using the SPI master controller on the Orion chips.
|
This enables using the SPI master controller on the Orion chips.
|
||||||
|
|
||||||
config SPI_PL022
|
config SPI_PL022
|
||||||
tristate "ARM AMBA PL022 SSP controller (EXPERIMENTAL)"
|
tristate "ARM AMBA PL022 SSP controller"
|
||||||
depends on ARM_AMBA && EXPERIMENTAL
|
depends on ARM_AMBA
|
||||||
default y if MACH_U300
|
default y if MACH_U300
|
||||||
default y if ARCH_REALVIEW
|
default y if ARCH_REALVIEW
|
||||||
default y if INTEGRATOR_IMPD1
|
default y if INTEGRATOR_IMPD1
|
||||||
|
|
|
@ -24,11 +24,6 @@
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO:
|
|
||||||
* - add timeout on polled transfers
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
@ -287,6 +282,8 @@
|
||||||
|
|
||||||
#define CLEAR_ALL_INTERRUPTS 0x3
|
#define CLEAR_ALL_INTERRUPTS 0x3
|
||||||
|
|
||||||
|
#define SPI_POLLING_TIMEOUT 1000
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The type of reading going on on this chip
|
* The type of reading going on on this chip
|
||||||
|
@ -1063,7 +1060,7 @@ static int __init pl022_dma_probe(struct pl022 *pl022)
|
||||||
pl022->master_info->dma_filter,
|
pl022->master_info->dma_filter,
|
||||||
pl022->master_info->dma_rx_param);
|
pl022->master_info->dma_rx_param);
|
||||||
if (!pl022->dma_rx_channel) {
|
if (!pl022->dma_rx_channel) {
|
||||||
dev_err(&pl022->adev->dev, "no RX DMA channel!\n");
|
dev_dbg(&pl022->adev->dev, "no RX DMA channel!\n");
|
||||||
goto err_no_rxchan;
|
goto err_no_rxchan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1071,13 +1068,13 @@ static int __init pl022_dma_probe(struct pl022 *pl022)
|
||||||
pl022->master_info->dma_filter,
|
pl022->master_info->dma_filter,
|
||||||
pl022->master_info->dma_tx_param);
|
pl022->master_info->dma_tx_param);
|
||||||
if (!pl022->dma_tx_channel) {
|
if (!pl022->dma_tx_channel) {
|
||||||
dev_err(&pl022->adev->dev, "no TX DMA channel!\n");
|
dev_dbg(&pl022->adev->dev, "no TX DMA channel!\n");
|
||||||
goto err_no_txchan;
|
goto err_no_txchan;
|
||||||
}
|
}
|
||||||
|
|
||||||
pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||||
if (!pl022->dummypage) {
|
if (!pl022->dummypage) {
|
||||||
dev_err(&pl022->adev->dev, "no DMA dummypage!\n");
|
dev_dbg(&pl022->adev->dev, "no DMA dummypage!\n");
|
||||||
goto err_no_dummypage;
|
goto err_no_dummypage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1093,6 +1090,8 @@ err_no_txchan:
|
||||||
dma_release_channel(pl022->dma_rx_channel);
|
dma_release_channel(pl022->dma_rx_channel);
|
||||||
pl022->dma_rx_channel = NULL;
|
pl022->dma_rx_channel = NULL;
|
||||||
err_no_rxchan:
|
err_no_rxchan:
|
||||||
|
dev_err(&pl022->adev->dev,
|
||||||
|
"Failed to work in dma mode, work without dma!\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1378,6 +1377,7 @@ static void do_polling_transfer(struct pl022 *pl022)
|
||||||
struct spi_transfer *transfer = NULL;
|
struct spi_transfer *transfer = NULL;
|
||||||
struct spi_transfer *previous = NULL;
|
struct spi_transfer *previous = NULL;
|
||||||
struct chip_data *chip;
|
struct chip_data *chip;
|
||||||
|
unsigned long time, timeout;
|
||||||
|
|
||||||
chip = pl022->cur_chip;
|
chip = pl022->cur_chip;
|
||||||
message = pl022->cur_msg;
|
message = pl022->cur_msg;
|
||||||
|
@ -1415,9 +1415,19 @@ static void do_polling_transfer(struct pl022 *pl022)
|
||||||
SSP_CR1(pl022->virtbase));
|
SSP_CR1(pl022->virtbase));
|
||||||
|
|
||||||
dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
|
dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n");
|
||||||
/* FIXME: insert a timeout so we don't hang here indefinitely */
|
|
||||||
while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end)
|
timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT);
|
||||||
|
while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) {
|
||||||
|
time = jiffies;
|
||||||
readwriter(pl022);
|
readwriter(pl022);
|
||||||
|
if (time_after(time, timeout)) {
|
||||||
|
dev_warn(&pl022->adev->dev,
|
||||||
|
"%s: timeout!\n", __func__);
|
||||||
|
message->state = STATE_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
cpu_relax();
|
||||||
|
}
|
||||||
|
|
||||||
/* Update total byte transferred */
|
/* Update total byte transferred */
|
||||||
message->actual_length += pl022->cur_transfer->len;
|
message->actual_length += pl022->cur_transfer->len;
|
||||||
|
@ -1426,7 +1436,7 @@ static void do_polling_transfer(struct pl022 *pl022)
|
||||||
/* Move to next transfer */
|
/* Move to next transfer */
|
||||||
message->state = next_transfer(pl022);
|
message->state = next_transfer(pl022);
|
||||||
}
|
}
|
||||||
|
out:
|
||||||
/* Handle end of message */
|
/* Handle end of message */
|
||||||
if (message->state == STATE_DONE)
|
if (message->state == STATE_DONE)
|
||||||
message->status = 0;
|
message->status = 0;
|
||||||
|
@ -2107,7 +2117,7 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
if (platform_info->enable_dma) {
|
if (platform_info->enable_dma) {
|
||||||
status = pl022_dma_probe(pl022);
|
status = pl022_dma_probe(pl022);
|
||||||
if (status != 0)
|
if (status != 0)
|
||||||
goto err_no_dma;
|
platform_info->enable_dma = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize and start queue */
|
/* Initialize and start queue */
|
||||||
|
@ -2143,7 +2153,6 @@ pl022_probe(struct amba_device *adev, const struct amba_id *id)
|
||||||
err_init_queue:
|
err_init_queue:
|
||||||
destroy_queue(pl022);
|
destroy_queue(pl022);
|
||||||
pl022_dma_remove(pl022);
|
pl022_dma_remove(pl022);
|
||||||
err_no_dma:
|
|
||||||
free_irq(adev->irq[0], pl022);
|
free_irq(adev->irq[0], pl022);
|
||||||
err_no_irq:
|
err_no_irq:
|
||||||
clk_put(pl022->clk);
|
clk_put(pl022->clk);
|
||||||
|
|
|
@ -58,8 +58,6 @@ struct chip_data {
|
||||||
u8 bits_per_word;
|
u8 bits_per_word;
|
||||||
u16 clk_div; /* baud rate divider */
|
u16 clk_div; /* baud rate divider */
|
||||||
u32 speed_hz; /* baud rate */
|
u32 speed_hz; /* baud rate */
|
||||||
int (*write)(struct dw_spi *dws);
|
|
||||||
int (*read)(struct dw_spi *dws);
|
|
||||||
void (*cs_control)(u32 command);
|
void (*cs_control)(u32 command);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,107 +160,70 @@ static inline void mrst_spi_debugfs_remove(struct dw_spi *dws)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_DEBUG_FS */
|
#endif /* CONFIG_DEBUG_FS */
|
||||||
|
|
||||||
static void wait_till_not_busy(struct dw_spi *dws)
|
/* Return the max entries we can fill into tx fifo */
|
||||||
|
static inline u32 tx_max(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
unsigned long end = jiffies + 1 + usecs_to_jiffies(5000);
|
u32 tx_left, tx_room, rxtx_gap;
|
||||||
|
|
||||||
while (time_before(jiffies, end)) {
|
tx_left = (dws->tx_end - dws->tx) / dws->n_bytes;
|
||||||
if (!(dw_readw(dws, sr) & SR_BUSY))
|
tx_room = dws->fifo_len - dw_readw(dws, txflr);
|
||||||
return;
|
|
||||||
cpu_relax();
|
/*
|
||||||
|
* Another concern is about the tx/rx mismatch, we
|
||||||
|
* though to use (dws->fifo_len - rxflr - txflr) as
|
||||||
|
* one maximum value for tx, but it doesn't cover the
|
||||||
|
* data which is out of tx/rx fifo and inside the
|
||||||
|
* shift registers. So a control from sw point of
|
||||||
|
* view is taken.
|
||||||
|
*/
|
||||||
|
rxtx_gap = ((dws->rx_end - dws->rx) - (dws->tx_end - dws->tx))
|
||||||
|
/ dws->n_bytes;
|
||||||
|
|
||||||
|
return min3(tx_left, tx_room, (u32) (dws->fifo_len - rxtx_gap));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the max entries we should read out of rx fifo */
|
||||||
|
static inline u32 rx_max(struct dw_spi *dws)
|
||||||
|
{
|
||||||
|
u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes;
|
||||||
|
|
||||||
|
return min(rx_left, (u32)dw_readw(dws, rxflr));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dw_writer(struct dw_spi *dws)
|
||||||
|
{
|
||||||
|
u32 max = tx_max(dws);
|
||||||
|
u16 txw = 0;
|
||||||
|
|
||||||
|
while (max--) {
|
||||||
|
/* Set the tx word if the transfer's original "tx" is not null */
|
||||||
|
if (dws->tx_end - dws->len) {
|
||||||
|
if (dws->n_bytes == 1)
|
||||||
|
txw = *(u8 *)(dws->tx);
|
||||||
|
else
|
||||||
|
txw = *(u16 *)(dws->tx);
|
||||||
}
|
}
|
||||||
dev_err(&dws->master->dev,
|
dw_writew(dws, dr, txw);
|
||||||
"DW SPI: Status keeps busy for 5000us after a read/write!\n");
|
dws->tx += dws->n_bytes;
|
||||||
}
|
|
||||||
|
|
||||||
static void flush(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
while (dw_readw(dws, sr) & SR_RF_NOT_EMPT) {
|
|
||||||
dw_readw(dws, dr);
|
|
||||||
cpu_relax();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_till_not_busy(dws);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int null_writer(struct dw_spi *dws)
|
static void dw_reader(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
u8 n_bytes = dws->n_bytes;
|
u32 max = rx_max(dws);
|
||||||
|
u16 rxw;
|
||||||
|
|
||||||
if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
|
while (max--) {
|
||||||
|| (dws->tx == dws->tx_end))
|
rxw = dw_readw(dws, dr);
|
||||||
return 0;
|
/* Care rx only if the transfer's original "rx" is not null */
|
||||||
dw_writew(dws, dr, 0);
|
if (dws->rx_end - dws->len) {
|
||||||
dws->tx += n_bytes;
|
if (dws->n_bytes == 1)
|
||||||
|
*(u8 *)(dws->rx) = rxw;
|
||||||
wait_till_not_busy(dws);
|
else
|
||||||
return 1;
|
*(u16 *)(dws->rx) = rxw;
|
||||||
}
|
|
||||||
|
|
||||||
static int null_reader(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
u8 n_bytes = dws->n_bytes;
|
|
||||||
|
|
||||||
while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
|
|
||||||
&& (dws->rx < dws->rx_end)) {
|
|
||||||
dw_readw(dws, dr);
|
|
||||||
dws->rx += n_bytes;
|
|
||||||
}
|
}
|
||||||
wait_till_not_busy(dws);
|
dws->rx += dws->n_bytes;
|
||||||
return dws->rx == dws->rx_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int u8_writer(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
|
|
||||||
|| (dws->tx == dws->tx_end))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dw_writew(dws, dr, *(u8 *)(dws->tx));
|
|
||||||
++dws->tx;
|
|
||||||
|
|
||||||
wait_till_not_busy(dws);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int u8_reader(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
|
|
||||||
&& (dws->rx < dws->rx_end)) {
|
|
||||||
*(u8 *)(dws->rx) = dw_readw(dws, dr);
|
|
||||||
++dws->rx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_till_not_busy(dws);
|
|
||||||
return dws->rx == dws->rx_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int u16_writer(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
if (!(dw_readw(dws, sr) & SR_TF_NOT_FULL)
|
|
||||||
|| (dws->tx == dws->tx_end))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
dw_writew(dws, dr, *(u16 *)(dws->tx));
|
|
||||||
dws->tx += 2;
|
|
||||||
|
|
||||||
wait_till_not_busy(dws);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int u16_reader(struct dw_spi *dws)
|
|
||||||
{
|
|
||||||
u16 temp;
|
|
||||||
|
|
||||||
while ((dw_readw(dws, sr) & SR_RF_NOT_EMPT)
|
|
||||||
&& (dws->rx < dws->rx_end)) {
|
|
||||||
temp = dw_readw(dws, dr);
|
|
||||||
*(u16 *)(dws->rx) = temp;
|
|
||||||
dws->rx += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
wait_till_not_busy(dws);
|
|
||||||
return dws->rx == dws->rx_end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *next_transfer(struct dw_spi *dws)
|
static void *next_transfer(struct dw_spi *dws)
|
||||||
|
@ -334,8 +295,7 @@ static void giveback(struct dw_spi *dws)
|
||||||
|
|
||||||
static void int_error_stop(struct dw_spi *dws, const char *msg)
|
static void int_error_stop(struct dw_spi *dws, const char *msg)
|
||||||
{
|
{
|
||||||
/* Stop and reset hw */
|
/* Stop the hw */
|
||||||
flush(dws);
|
|
||||||
spi_enable_chip(dws, 0);
|
spi_enable_chip(dws, 0);
|
||||||
|
|
||||||
dev_err(&dws->master->dev, "%s\n", msg);
|
dev_err(&dws->master->dev, "%s\n", msg);
|
||||||
|
@ -362,35 +322,28 @@ EXPORT_SYMBOL_GPL(dw_spi_xfer_done);
|
||||||
|
|
||||||
static irqreturn_t interrupt_transfer(struct dw_spi *dws)
|
static irqreturn_t interrupt_transfer(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
u16 irq_status, irq_mask = 0x3f;
|
u16 irq_status = dw_readw(dws, isr);
|
||||||
u32 int_level = dws->fifo_len / 2;
|
|
||||||
u32 left;
|
|
||||||
|
|
||||||
irq_status = dw_readw(dws, isr) & irq_mask;
|
|
||||||
/* Error handling */
|
/* Error handling */
|
||||||
if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
|
if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) {
|
||||||
dw_readw(dws, txoicr);
|
dw_readw(dws, txoicr);
|
||||||
dw_readw(dws, rxoicr);
|
dw_readw(dws, rxoicr);
|
||||||
dw_readw(dws, rxuicr);
|
dw_readw(dws, rxuicr);
|
||||||
int_error_stop(dws, "interrupt_transfer: fifo overrun");
|
int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun");
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dw_reader(dws);
|
||||||
|
if (dws->rx_end == dws->rx) {
|
||||||
|
spi_mask_intr(dws, SPI_INT_TXEI);
|
||||||
|
dw_spi_xfer_done(dws);
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
if (irq_status & SPI_INT_TXEI) {
|
if (irq_status & SPI_INT_TXEI) {
|
||||||
spi_mask_intr(dws, SPI_INT_TXEI);
|
spi_mask_intr(dws, SPI_INT_TXEI);
|
||||||
|
dw_writer(dws);
|
||||||
left = (dws->tx_end - dws->tx) / dws->n_bytes;
|
/* Enable TX irq always, it will be disabled when RX finished */
|
||||||
left = (left > int_level) ? int_level : left;
|
|
||||||
|
|
||||||
while (left--)
|
|
||||||
dws->write(dws);
|
|
||||||
dws->read(dws);
|
|
||||||
|
|
||||||
/* Re-enable the IRQ if there is still data left to tx */
|
|
||||||
if (dws->tx_end > dws->tx)
|
|
||||||
spi_umask_intr(dws, SPI_INT_TXEI);
|
spi_umask_intr(dws, SPI_INT_TXEI);
|
||||||
else
|
|
||||||
dw_spi_xfer_done(dws);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@ -399,15 +352,13 @@ static irqreturn_t interrupt_transfer(struct dw_spi *dws)
|
||||||
static irqreturn_t dw_spi_irq(int irq, void *dev_id)
|
static irqreturn_t dw_spi_irq(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct dw_spi *dws = dev_id;
|
struct dw_spi *dws = dev_id;
|
||||||
u16 irq_status, irq_mask = 0x3f;
|
u16 irq_status = dw_readw(dws, isr) & 0x3f;
|
||||||
|
|
||||||
irq_status = dw_readw(dws, isr) & irq_mask;
|
|
||||||
if (!irq_status)
|
if (!irq_status)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
if (!dws->cur_msg) {
|
if (!dws->cur_msg) {
|
||||||
spi_mask_intr(dws, SPI_INT_TXEI);
|
spi_mask_intr(dws, SPI_INT_TXEI);
|
||||||
/* Never fail */
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,13 +368,11 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
|
||||||
/* Must be called inside pump_transfers() */
|
/* Must be called inside pump_transfers() */
|
||||||
static void poll_transfer(struct dw_spi *dws)
|
static void poll_transfer(struct dw_spi *dws)
|
||||||
{
|
{
|
||||||
while (dws->write(dws))
|
do {
|
||||||
dws->read(dws);
|
dw_writer(dws);
|
||||||
/*
|
dw_reader(dws);
|
||||||
* There is a possibility that the last word of a transaction
|
cpu_relax();
|
||||||
* will be lost if data is not ready. Re-read to solve this issue.
|
} while (dws->rx_end > dws->rx);
|
||||||
*/
|
|
||||||
dws->read(dws);
|
|
||||||
|
|
||||||
dw_spi_xfer_done(dws);
|
dw_spi_xfer_done(dws);
|
||||||
}
|
}
|
||||||
|
@ -483,8 +432,6 @@ static void pump_transfers(unsigned long data)
|
||||||
dws->tx_end = dws->tx + transfer->len;
|
dws->tx_end = dws->tx + transfer->len;
|
||||||
dws->rx = transfer->rx_buf;
|
dws->rx = transfer->rx_buf;
|
||||||
dws->rx_end = dws->rx + transfer->len;
|
dws->rx_end = dws->rx + transfer->len;
|
||||||
dws->write = dws->tx ? chip->write : null_writer;
|
|
||||||
dws->read = dws->rx ? chip->read : null_reader;
|
|
||||||
dws->cs_change = transfer->cs_change;
|
dws->cs_change = transfer->cs_change;
|
||||||
dws->len = dws->cur_transfer->len;
|
dws->len = dws->cur_transfer->len;
|
||||||
if (chip != dws->prev_chip)
|
if (chip != dws->prev_chip)
|
||||||
|
@ -518,20 +465,8 @@ static void pump_transfers(unsigned long data)
|
||||||
|
|
||||||
switch (bits) {
|
switch (bits) {
|
||||||
case 8:
|
case 8:
|
||||||
dws->n_bytes = 1;
|
|
||||||
dws->dma_width = 1;
|
|
||||||
dws->read = (dws->read != null_reader) ?
|
|
||||||
u8_reader : null_reader;
|
|
||||||
dws->write = (dws->write != null_writer) ?
|
|
||||||
u8_writer : null_writer;
|
|
||||||
break;
|
|
||||||
case 16:
|
case 16:
|
||||||
dws->n_bytes = 2;
|
dws->n_bytes = dws->dma_width = bits >> 3;
|
||||||
dws->dma_width = 2;
|
|
||||||
dws->read = (dws->read != null_reader) ?
|
|
||||||
u16_reader : null_reader;
|
|
||||||
dws->write = (dws->write != null_writer) ?
|
|
||||||
u16_writer : null_writer;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printk(KERN_ERR "MRST SPI0: unsupported bits:"
|
printk(KERN_ERR "MRST SPI0: unsupported bits:"
|
||||||
|
@ -575,7 +510,7 @@ static void pump_transfers(unsigned long data)
|
||||||
txint_level = dws->fifo_len / 2;
|
txint_level = dws->fifo_len / 2;
|
||||||
txint_level = (templen > txint_level) ? txint_level : templen;
|
txint_level = (templen > txint_level) ? txint_level : templen;
|
||||||
|
|
||||||
imask |= SPI_INT_TXEI;
|
imask |= SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI;
|
||||||
dws->transfer_handler = interrupt_transfer;
|
dws->transfer_handler = interrupt_transfer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -733,13 +668,9 @@ static int dw_spi_setup(struct spi_device *spi)
|
||||||
if (spi->bits_per_word <= 8) {
|
if (spi->bits_per_word <= 8) {
|
||||||
chip->n_bytes = 1;
|
chip->n_bytes = 1;
|
||||||
chip->dma_width = 1;
|
chip->dma_width = 1;
|
||||||
chip->read = u8_reader;
|
|
||||||
chip->write = u8_writer;
|
|
||||||
} else if (spi->bits_per_word <= 16) {
|
} else if (spi->bits_per_word <= 16) {
|
||||||
chip->n_bytes = 2;
|
chip->n_bytes = 2;
|
||||||
chip->dma_width = 2;
|
chip->dma_width = 2;
|
||||||
chip->read = u16_reader;
|
|
||||||
chip->write = u16_writer;
|
|
||||||
} else {
|
} else {
|
||||||
/* Never take >16b case for MRST SPIC */
|
/* Never take >16b case for MRST SPIC */
|
||||||
dev_err(&spi->dev, "invalid wordsize\n");
|
dev_err(&spi->dev, "invalid wordsize\n");
|
||||||
|
@ -851,7 +782,6 @@ static void spi_hw_init(struct dw_spi *dws)
|
||||||
spi_enable_chip(dws, 0);
|
spi_enable_chip(dws, 0);
|
||||||
spi_mask_intr(dws, 0xff);
|
spi_mask_intr(dws, 0xff);
|
||||||
spi_enable_chip(dws, 1);
|
spi_enable_chip(dws, 1);
|
||||||
flush(dws);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Try to detect the FIFO depth if not set by interface driver,
|
* Try to detect the FIFO depth if not set by interface driver,
|
||||||
|
|
|
@ -137,8 +137,6 @@ struct dw_spi {
|
||||||
u8 max_bits_per_word; /* maxim is 16b */
|
u8 max_bits_per_word; /* maxim is 16b */
|
||||||
u32 dma_width;
|
u32 dma_width;
|
||||||
int cs_change;
|
int cs_change;
|
||||||
int (*write)(struct dw_spi *dws);
|
|
||||||
int (*read)(struct dw_spi *dws);
|
|
||||||
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
irqreturn_t (*transfer_handler)(struct dw_spi *dws);
|
||||||
void (*cs_control)(u32 command);
|
void (*cs_control)(u32 command);
|
||||||
|
|
||||||
|
|
|
@ -1047,8 +1047,8 @@ static u8 *buf;
|
||||||
* spi_{async,sync}() calls with dma-safe buffers.
|
* spi_{async,sync}() calls with dma-safe buffers.
|
||||||
*/
|
*/
|
||||||
int spi_write_then_read(struct spi_device *spi,
|
int spi_write_then_read(struct spi_device *spi,
|
||||||
const u8 *txbuf, unsigned n_tx,
|
const void *txbuf, unsigned n_tx,
|
||||||
u8 *rxbuf, unsigned n_rx)
|
void *rxbuf, unsigned n_rx)
|
||||||
{
|
{
|
||||||
static DEFINE_MUTEX(lock);
|
static DEFINE_MUTEX(lock);
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,7 @@ static int __devexit nuc900_spi_remove(struct platform_device *dev)
|
||||||
|
|
||||||
platform_set_drvdata(dev, NULL);
|
platform_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
spi_unregister_master(hw->master);
|
spi_bitbang_stop(&hw->bitbang);
|
||||||
|
|
||||||
clk_disable(hw->clk);
|
clk_disable(hw->clk);
|
||||||
clk_put(hw->clk);
|
clk_put(hw->clk);
|
||||||
|
|
|
@ -668,7 +668,7 @@ static int __exit s3c24xx_spi_remove(struct platform_device *dev)
|
||||||
|
|
||||||
platform_set_drvdata(dev, NULL);
|
platform_set_drvdata(dev, NULL);
|
||||||
|
|
||||||
spi_unregister_master(hw->master);
|
spi_bitbang_stop(&hw->bitbang);
|
||||||
|
|
||||||
clk_disable(hw->clk);
|
clk_disable(hw->clk);
|
||||||
clk_put(hw->clk);
|
clk_put(hw->clk);
|
||||||
|
|
|
@ -427,10 +427,10 @@ static int __devexit spi_sh_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev);
|
struct spi_sh_data *ss = dev_get_drvdata(&pdev->dev);
|
||||||
|
|
||||||
|
spi_unregister_master(ss->master);
|
||||||
destroy_workqueue(ss->workqueue);
|
destroy_workqueue(ss->workqueue);
|
||||||
free_irq(ss->irq, ss);
|
free_irq(ss->irq, ss);
|
||||||
iounmap(ss->addr);
|
iounmap(ss->addr);
|
||||||
spi_master_put(ss->master);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -578,6 +578,7 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
|
||||||
master = dev_get_drvdata(&pdev->dev);
|
master = dev_get_drvdata(&pdev->dev);
|
||||||
tspi = spi_master_get_devdata(master);
|
tspi = spi_master_get_devdata(master);
|
||||||
|
|
||||||
|
spi_unregister_master(master);
|
||||||
tegra_dma_free_channel(tspi->rx_dma);
|
tegra_dma_free_channel(tspi->rx_dma);
|
||||||
|
|
||||||
dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
|
dma_free_coherent(&pdev->dev, sizeof(u32) * BB_LEN,
|
||||||
|
@ -586,7 +587,6 @@ static int __devexit spi_tegra_remove(struct platform_device *pdev)
|
||||||
clk_put(tspi->clk);
|
clk_put(tspi->clk);
|
||||||
iounmap(tspi->base);
|
iounmap(tspi->base);
|
||||||
|
|
||||||
spi_master_put(master);
|
|
||||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
release_mem_region(r->start, (r->end - r->start) + 1);
|
release_mem_region(r->start, (r->end - r->start) + 1);
|
||||||
|
|
||||||
|
|
|
@ -581,7 +581,7 @@ extern int spi_bus_unlock(struct spi_master *master);
|
||||||
* Callable only from contexts that can sleep.
|
* Callable only from contexts that can sleep.
|
||||||
*/
|
*/
|
||||||
static inline int
|
static inline int
|
||||||
spi_write(struct spi_device *spi, const u8 *buf, size_t len)
|
spi_write(struct spi_device *spi, const void *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct spi_transfer t = {
|
struct spi_transfer t = {
|
||||||
.tx_buf = buf,
|
.tx_buf = buf,
|
||||||
|
@ -605,7 +605,7 @@ spi_write(struct spi_device *spi, const u8 *buf, size_t len)
|
||||||
* Callable only from contexts that can sleep.
|
* Callable only from contexts that can sleep.
|
||||||
*/
|
*/
|
||||||
static inline int
|
static inline int
|
||||||
spi_read(struct spi_device *spi, u8 *buf, size_t len)
|
spi_read(struct spi_device *spi, void *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct spi_transfer t = {
|
struct spi_transfer t = {
|
||||||
.rx_buf = buf,
|
.rx_buf = buf,
|
||||||
|
@ -620,8 +620,8 @@ spi_read(struct spi_device *spi, u8 *buf, size_t len)
|
||||||
|
|
||||||
/* this copies txbuf and rxbuf data; for small transfers only! */
|
/* this copies txbuf and rxbuf data; for small transfers only! */
|
||||||
extern int spi_write_then_read(struct spi_device *spi,
|
extern int spi_write_then_read(struct spi_device *spi,
|
||||||
const u8 *txbuf, unsigned n_tx,
|
const void *txbuf, unsigned n_tx,
|
||||||
u8 *rxbuf, unsigned n_rx);
|
void *rxbuf, unsigned n_rx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
|
* spi_w8r8 - SPI synchronous 8 bit write followed by 8 bit read
|
||||||
|
|
Loading…
Reference in a new issue