summaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2010-12-22 18:57:02 +0100
committerJiri Kosina <jkosina@suse.cz>2010-12-22 18:57:02 +0100
commit4b7bd364700d9ac8372eff48832062b936d0793b (patch)
tree0dbf78c95456a0b02d07fcd473281f04a87e266d /drivers/spi
parentc0d8768af260e2cbb4bf659ae6094a262c86b085 (diff)
parent90a8a73c06cc32b609a880d48449d7083327e11a (diff)
downloadop-kernel-dev-4b7bd364700d9ac8372eff48832062b936d0793b.zip
op-kernel-dev-4b7bd364700d9ac8372eff48832062b936d0793b.tar.gz
Merge branch 'master' into for-next
Conflicts: MAINTAINERS arch/arm/mach-omap2/pm24xx.c drivers/scsi/bfa/bfa_fcpim.c Needed to update to apply fixes for which the old branch was too outdated.
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/atmel_spi.c6
-rw-r--r--drivers/spi/dw_spi.c5
-rw-r--r--drivers/spi/spi.c98
-rw-r--r--drivers/spi/spi_bfin5xx.c22
4 files changed, 79 insertions, 52 deletions
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 49596a1..1a478bf 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -352,8 +352,12 @@ atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
if (xfer->tx_buf) {
+ /* tx_buf is a const void* where we need a void * for the dma
+ * mapping */
+ void *nonconst_tx = (void *)xfer->tx_buf;
+
xfer->tx_dma = dma_map_single(dev,
- (void *) xfer->tx_buf, xfer->len,
+ nonconst_tx, xfer->len,
DMA_TO_DEVICE);
if (dma_mapping_error(dev, xfer->tx_dma))
return -ENOMEM;
diff --git a/drivers/spi/dw_spi.c b/drivers/spi/dw_spi.c
index 9043931..0838c79 100644
--- a/drivers/spi/dw_spi.c
+++ b/drivers/spi/dw_spi.c
@@ -413,6 +413,11 @@ static void poll_transfer(struct dw_spi *dws)
{
while (dws->write(dws))
dws->read(dws);
+ /*
+ * There is a possibility that the last word of a transaction
+ * will be lost if data is not ready. Re-read to solve this issue.
+ */
+ dws->read(dws);
transfer_complete(dws);
}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index b5a78a1..709c836 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -29,11 +29,6 @@
#include <linux/spi/spi.h>
#include <linux/of_spi.h>
-
-/* SPI bustype and spi_master class are registered after board init code
- * provides the SPI device tables, ensuring that both are present by the
- * time controller driver registration causes spi_devices to "enumerate".
- */
static void spidev_release(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
@@ -202,11 +197,16 @@ EXPORT_SYMBOL_GPL(spi_register_driver);
struct boardinfo {
struct list_head list;
- unsigned n_board_info;
- struct spi_board_info board_info[0];
+ struct spi_board_info board_info;
};
static LIST_HEAD(board_list);
+static LIST_HEAD(spi_master_list);
+
+/*
+ * Used to protect add/del opertion for board_info list and
+ * spi_master list, and their matching process
+ */
static DEFINE_MUTEX(board_lock);
/**
@@ -300,16 +300,16 @@ int spi_add_device(struct spi_device *spi)
*/
status = spi_setup(spi);
if (status < 0) {
- dev_err(dev, "can't %s %s, status %d\n",
- "setup", dev_name(&spi->dev), status);
+ dev_err(dev, "can't setup %s, status %d\n",
+ dev_name(&spi->dev), status);
goto done;
}
/* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev);
if (status < 0)
- dev_err(dev, "can't %s %s, status %d\n",
- "add", dev_name(&spi->dev), status);
+ dev_err(dev, "can't add %s, status %d\n",
+ dev_name(&spi->dev), status);
else
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
@@ -371,6 +371,20 @@ struct spi_device *spi_new_device(struct spi_master *master,
}
EXPORT_SYMBOL_GPL(spi_new_device);
+static void spi_match_master_to_boardinfo(struct spi_master *master,
+ struct spi_board_info *bi)
+{
+ struct spi_device *dev;
+
+ if (master->bus_num != bi->bus_num)
+ return;
+
+ dev = spi_new_device(master, bi);
+ if (!dev)
+ dev_err(master->dev.parent, "can't create new device for %s\n",
+ bi->modalias);
+}
+
/**
* spi_register_board_info - register SPI devices for a given board
* @info: array of chip descriptors
@@ -393,43 +407,25 @@ EXPORT_SYMBOL_GPL(spi_new_device);
int __init
spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
- struct boardinfo *bi;
+ struct boardinfo *bi;
+ int i;
- bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
+ bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
if (!bi)
return -ENOMEM;
- bi->n_board_info = n;
- memcpy(bi->board_info, info, n * sizeof *info);
- mutex_lock(&board_lock);
- list_add_tail(&bi->list, &board_list);
- mutex_unlock(&board_lock);
- return 0;
-}
+ for (i = 0; i < n; i++, bi++, info++) {
+ struct spi_master *master;
-/* FIXME someone should add support for a __setup("spi", ...) that
- * creates board info from kernel command lines
- */
-
-static void scan_boardinfo(struct spi_master *master)
-{
- struct boardinfo *bi;
-
- mutex_lock(&board_lock);
- list_for_each_entry(bi, &board_list, list) {
- struct spi_board_info *chip = bi->board_info;
- unsigned n;
-
- for (n = bi->n_board_info; n > 0; n--, chip++) {
- if (chip->bus_num != master->bus_num)
- continue;
- /* NOTE: this relies on spi_new_device to
- * issue diagnostics when given bogus inputs
- */
- (void) spi_new_device(master, chip);
- }
+ memcpy(&bi->board_info, info, sizeof(*info));
+ mutex_lock(&board_lock);
+ list_add_tail(&bi->list, &board_list);
+ list_for_each_entry(master, &spi_master_list, list)
+ spi_match_master_to_boardinfo(master, &bi->board_info);
+ mutex_unlock(&board_lock);
}
- mutex_unlock(&board_lock);
+
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -512,6 +508,7 @@ int spi_register_master(struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
struct device *dev = master->dev.parent;
+ struct boardinfo *bi;
int status = -ENODEV;
int dynamic = 0;
@@ -547,8 +544,12 @@ int spi_register_master(struct spi_master *master)
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");
- /* populate children from any spi device tables */
- scan_boardinfo(master);
+ mutex_lock(&board_lock);
+ list_add_tail(&master->list, &spi_master_list);
+ list_for_each_entry(bi, &board_list, list)
+ spi_match_master_to_boardinfo(master, &bi->board_info);
+ mutex_unlock(&board_lock);
+
status = 0;
/* Register devices from the device tree */
@@ -579,7 +580,12 @@ void spi_unregister_master(struct spi_master *master)
{
int dummy;
- dummy = device_for_each_child(&master->dev, NULL, __unregister);
+ mutex_lock(&board_lock);
+ list_del(&master->list);
+ mutex_unlock(&board_lock);
+
+ dummy = device_for_each_child(master->dev.parent, &master->dev,
+ __unregister);
device_unregister(&master->dev);
}
EXPORT_SYMBOL_GPL(spi_unregister_master);
@@ -652,7 +658,7 @@ int spi_setup(struct spi_device *spi)
*/
bad_bits = spi->mode & ~spi->master->mode_bits;
if (bad_bits) {
- dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+ dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
bad_bits);
return -EINVAL;
}
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index ab483a0..3f22351 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -504,6 +504,15 @@ static irqreturn_t bfin_spi_dma_irq_handler(int irq, void *dev_id)
"in dma_irq_handler dmastat:0x%x spistat:0x%x\n",
dmastat, spistat);
+ if (drv_data->rx != NULL) {
+ u16 cr = read_CTRL(drv_data);
+ /* discard old RX data and clear RXS */
+ bfin_spi_dummy_read(drv_data);
+ write_CTRL(drv_data, cr & ~BIT_CTL_ENABLE); /* Disable SPI */
+ write_CTRL(drv_data, cr & ~BIT_CTL_TIMOD); /* Restore State */
+ write_STAT(drv_data, BIT_STAT_CLR); /* Clear Status */
+ }
+
clear_dma_irqstat(drv_data->dma_channel);
/*
@@ -1099,12 +1108,15 @@ static int bfin_spi_setup(struct spi_device *spi)
}
if (chip->chip_select_num >= MAX_CTRL_CS) {
- ret = gpio_request(chip->cs_gpio, spi->modalias);
- if (ret) {
- dev_err(&spi->dev, "gpio_request() error\n");
- goto pin_error;
+ /* Only request on first setup */
+ if (spi_get_ctldata(spi) == NULL) {
+ ret = gpio_request(chip->cs_gpio, spi->modalias);
+ if (ret) {
+ dev_err(&spi->dev, "gpio_request() error\n");
+ goto pin_error;
+ }
+ gpio_direction_output(chip->cs_gpio, 1);
}
- gpio_direction_output(chip->cs_gpio, 1);
}
dev_dbg(&spi->dev, "setup spi chip %s, width is %d, dma is %d\n",
OpenPOWER on IntegriCloud