summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2014-08-18 06:46:34 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2014-08-18 06:46:34 +1000
commit40cf1f11dc621201beb85c4e254ee343d4fa72ae (patch)
treec326ff980f7aa5d157becb9468cd43fb6921a577 /drivers
parent02d31d07ea43fca0db4a9af97340d21f7183ba2a (diff)
parenta58bfa1599ce11de8b6d008a9bf6971f353a1489 (diff)
Merge remote-tracking branch 'spi/for-next'
Diffstat (limited to 'drivers')
-rw-r--r--drivers/spi/Kconfig2
-rw-r--r--drivers/spi/spi-cadence.c1
-rw-r--r--drivers/spi/spi-omap-100k.c4
-rw-r--r--drivers/spi/spi-omap2-mcspi.c3
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c21
-rw-r--r--drivers/spi/spi-rspi.c147
-rw-r--r--drivers/spi/spi-sh-msiof.c100
-rw-r--r--drivers/spi/spi-xilinx.c1
-rw-r--r--drivers/spi/spi.c1
9 files changed, 171 insertions, 109 deletions
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 62e2242ad7e0..aa005cbf2e50 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -380,7 +380,7 @@ config SPI_PXA2XX
additional documentation can be found a Documentation/spi/pxa2xx.
config SPI_PXA2XX_PCI
- def_tristate SPI_PXA2XX && PCI
+ def_tristate SPI_PXA2XX && PCI && COMMON_CLK
config SPI_ROCKCHIP
tristate "Rockchip SPI controller driver"
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index 562ff83debd9..7b811e38c7ad 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -677,7 +677,6 @@ static struct platform_driver cdns_spi_driver = {
.remove = cdns_spi_remove,
.driver = {
.name = CDNS_SPI_NAME,
- .owner = THIS_MODULE,
.of_match_table = cdns_spi_of_match,
.pm = &cdns_spi_dev_pm_ops,
},
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 5e91858f6f01..fb522765ce5a 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -70,10 +70,6 @@
#define SPI_STATUS_WE (1UL << 1)
#define SPI_STATUS_RD (1UL << 0)
-#define WRITE 0
-#define READ 1
-
-
/* use PIO for small transfers, avoiding DMA setup/teardown overhead and
* cache operations; better heuristics consider wordsize and bitrate.
*/
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 68441fa448de..352eed7463ac 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -329,7 +329,8 @@ static void omap2_mcspi_set_fifo(const struct spi_device *spi,
disable_fifo:
if (t->rx_buf != NULL)
chconf &= ~OMAP2_MCSPI_CHCONF_FFER;
- else
+
+ if (t->tx_buf != NULL)
chconf &= ~OMAP2_MCSPI_CHCONF_FFET;
mcspi_write_chconf0(spi, chconf);
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index c1865c92ccb9..20ebbc764693 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -7,6 +7,8 @@
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/spi/pxa2xx_spi.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
enum {
PORT_CE4100,
@@ -21,6 +23,7 @@ struct pxa_spi_info {
int tx_chan_id;
int rx_slave_id;
int rx_chan_id;
+ unsigned long max_clk_rate;
};
static struct pxa_spi_info spi_info_configs[] = {
@@ -32,6 +35,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.tx_chan_id = -1,
.rx_slave_id = -1,
.rx_chan_id = -1,
+ .max_clk_rate = 3686400,
},
[PORT_BYT] = {
.type = LPSS_SSP,
@@ -41,6 +45,7 @@ static struct pxa_spi_info spi_info_configs[] = {
.tx_chan_id = 0,
.rx_slave_id = 1,
.rx_chan_id = 1,
+ .max_clk_rate = 50000000,
},
};
@@ -53,6 +58,7 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
struct pxa2xx_spi_master spi_pdata;
struct ssp_device *ssp;
struct pxa_spi_info *c;
+ char buf[40];
ret = pcim_enable_device(dev);
if (ret)
@@ -84,6 +90,12 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
ssp->port_id = (c->port_id >= 0) ? c->port_id : dev->devfn;
ssp->type = c->type;
+ snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id);
+ ssp->clk = clk_register_fixed_rate(&dev->dev, buf , NULL,
+ CLK_IS_ROOT, c->max_clk_rate);
+ if (IS_ERR(ssp->clk))
+ return PTR_ERR(ssp->clk);
+
memset(&pi, 0, sizeof(pi));
pi.parent = &dev->dev;
pi.name = "pxa2xx-spi";
@@ -92,8 +104,10 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
pi.size_data = sizeof(spi_pdata);
pdev = platform_device_register_full(&pi);
- if (IS_ERR(pdev))
+ if (IS_ERR(pdev)) {
+ clk_unregister(ssp->clk);
return PTR_ERR(pdev);
+ }
pci_set_drvdata(dev, pdev);
@@ -103,8 +117,13 @@ static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
{
struct platform_device *pdev = pci_get_drvdata(dev);
+ struct pxa2xx_spi_master *spi_pdata;
+
+ spi_pdata = dev_get_platdata(&pdev->dev);
platform_device_unregister(pdev);
+ clk_unregister(spi_pdata->ssp.clk);
+ pci_set_drvdata(dev, NULL);
}
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index c850dfdfa9e3..1da609e4491d 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -472,25 +472,52 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
dma_cookie_t cookie;
int ret;
- if (tx) {
- desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
- tx->sgl, tx->nents, DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_tx)
- goto no_dma;
-
- irq_mask |= SPCR_SPTIE;
- }
+ /* First prepare and submit the DMA request(s), as this may fail */
if (rx) {
desc_rx = dmaengine_prep_slave_sg(rspi->master->dma_rx,
rx->sgl, rx->nents, DMA_FROM_DEVICE,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_rx)
- goto no_dma;
+ if (!desc_rx) {
+ ret = -EAGAIN;
+ goto no_dma_rx;
+ }
+
+ desc_rx->callback = rspi_dma_complete;
+ desc_rx->callback_param = rspi;
+ cookie = dmaengine_submit(desc_rx);
+ if (dma_submit_error(cookie)) {
+ ret = cookie;
+ goto no_dma_rx;
+ }
irq_mask |= SPCR_SPRIE;
}
+ if (tx) {
+ desc_tx = dmaengine_prep_slave_sg(rspi->master->dma_tx,
+ tx->sgl, tx->nents, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_tx) {
+ ret = -EAGAIN;
+ goto no_dma_tx;
+ }
+
+ if (rx) {
+ /* No callback */
+ desc_tx->callback = NULL;
+ } else {
+ desc_tx->callback = rspi_dma_complete;
+ desc_tx->callback_param = rspi;
+ }
+ cookie = dmaengine_submit(desc_tx);
+ if (dma_submit_error(cookie)) {
+ ret = cookie;
+ goto no_dma_tx;
+ }
+
+ irq_mask |= SPCR_SPTIE;
+ }
+
/*
* DMAC needs SPxIE, but if SPxIE is set, the IRQ routine will be
* called. So, this driver disables the IRQ while DMA transfer.
@@ -503,34 +530,24 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
rspi_enable_irq(rspi, irq_mask);
rspi->dma_callbacked = 0;
- if (rx) {
- desc_rx->callback = rspi_dma_complete;
- desc_rx->callback_param = rspi;
- cookie = dmaengine_submit(desc_rx);
- if (dma_submit_error(cookie))
- return cookie;
+ /* Now start DMA */
+ if (rx)
dma_async_issue_pending(rspi->master->dma_rx);
- }
- if (tx) {
- if (rx) {
- /* No callback */
- desc_tx->callback = NULL;
- } else {
- desc_tx->callback = rspi_dma_complete;
- desc_tx->callback_param = rspi;
- }
- cookie = dmaengine_submit(desc_tx);
- if (dma_submit_error(cookie))
- return cookie;
+ if (tx)
dma_async_issue_pending(rspi->master->dma_tx);
- }
ret = wait_event_interruptible_timeout(rspi->wait,
rspi->dma_callbacked, HZ);
if (ret > 0 && rspi->dma_callbacked)
ret = 0;
- else if (!ret)
+ else if (!ret) {
+ dev_err(&rspi->master->dev, "DMA timeout\n");
ret = -ETIMEDOUT;
+ if (tx)
+ dmaengine_terminate_all(rspi->master->dma_tx);
+ if (rx)
+ dmaengine_terminate_all(rspi->master->dma_rx);
+ }
rspi_disable_irq(rspi, irq_mask);
@@ -541,11 +558,16 @@ static int rspi_dma_transfer(struct rspi_data *rspi, struct sg_table *tx,
return ret;
-no_dma:
- pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
- dev_driver_string(&rspi->master->dev),
- dev_name(&rspi->master->dev));
- return -EAGAIN;
+no_dma_tx:
+ if (rx)
+ dmaengine_terminate_all(rspi->master->dma_rx);
+no_dma_rx:
+ if (ret == -EAGAIN) {
+ pr_warn_once("%s %s: DMA not available, falling back to PIO\n",
+ dev_driver_string(&rspi->master->dev),
+ dev_name(&rspi->master->dev));
+ }
+ return ret;
}
static void rspi_receive_init(const struct rspi_data *rspi)
@@ -887,20 +909,24 @@ static struct dma_chan *rspi_request_dma_chan(struct device *dev,
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- chan = dma_request_channel(mask, shdma_chan_filter,
- (void *)(unsigned long)id);
+ chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+ (void *)(unsigned long)id, dev,
+ dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) {
- dev_warn(dev, "dma_request_channel failed\n");
+ dev_warn(dev, "dma_request_slave_channel_compat failed\n");
return NULL;
}
memset(&cfg, 0, sizeof(cfg));
cfg.slave_id = id;
cfg.direction = dir;
- if (dir == DMA_MEM_TO_DEV)
+ if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = port_addr;
- else
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ } else {
cfg.src_addr = port_addr;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ }
ret = dmaengine_slave_config(chan, &cfg);
if (ret) {
@@ -916,22 +942,30 @@ static int rspi_request_dma(struct device *dev, struct spi_master *master,
const struct resource *res)
{
const struct rspi_plat_data *rspi_pd = dev_get_platdata(dev);
+ unsigned int dma_tx_id, dma_rx_id;
+
+ if (dev->of_node) {
+ /* In the OF case we will get the slave IDs from the DT */
+ dma_tx_id = 0;
+ dma_rx_id = 0;
+ } else if (rspi_pd && rspi_pd->dma_tx_id && rspi_pd->dma_rx_id) {
+ dma_tx_id = rspi_pd->dma_tx_id;
+ dma_rx_id = rspi_pd->dma_rx_id;
+ } else {
+ /* The driver assumes no error. */
+ return 0;
+ }
- if (!rspi_pd || !rspi_pd->dma_rx_id || !rspi_pd->dma_tx_id)
- return 0; /* The driver assumes no error. */
-
- master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM,
- rspi_pd->dma_rx_id,
+ master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV, dma_tx_id,
res->start + RSPI_SPDR);
- if (!master->dma_rx)
+ if (!master->dma_tx)
return -ENODEV;
- master->dma_tx = rspi_request_dma_chan(dev, DMA_MEM_TO_DEV,
- rspi_pd->dma_tx_id,
+ master->dma_rx = rspi_request_dma_chan(dev, DMA_DEV_TO_MEM, dma_rx_id,
res->start + RSPI_SPDR);
- if (!master->dma_tx) {
- dma_release_channel(master->dma_rx);
- master->dma_rx = NULL;
+ if (!master->dma_rx) {
+ dma_release_channel(master->dma_tx);
+ master->dma_tx = NULL;
return -ENODEV;
}
@@ -1024,12 +1058,11 @@ static int rspi_request_irq(struct device *dev, unsigned int irq,
irq_handler_t handler, const char *suffix,
void *dev_id)
{
- const char *base = dev_name(dev);
- size_t len = strlen(base) + strlen(suffix) + 2;
- char *name = devm_kzalloc(dev, len, GFP_KERNEL);
+ const char *name = devm_kasprintf(dev, GFP_KERNEL, "%s:%s",
+ dev_name(dev), suffix);
if (!name)
return -ENOMEM;
- snprintf(name, len, "%s:%s", base, suffix);
+
return devm_request_irq(dev, irq, handler, 0, name, dev_id);
}
@@ -1062,7 +1095,7 @@ static int rspi_probe(struct platform_device *pdev)
master->num_chipselect = rspi_pd->num_chipselect;
else
master->num_chipselect = 2; /* default */
- };
+ }
/* ops parameter check */
if (!ops->set_config_register) {
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 2a4354dcd661..1165d418340f 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -636,17 +636,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
dma_cookie_t cookie;
int ret;
- if (tx) {
- ier_bits |= IER_TDREQE | IER_TDMAE;
- dma_sync_single_for_device(p->master->dma_tx->device->dev,
- p->tx_dma_addr, len, DMA_TO_DEVICE);
- desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
- p->tx_dma_addr, len, DMA_TO_DEVICE,
- DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- if (!desc_tx)
- return -EAGAIN;
- }
-
+ /* First prepare and submit the DMA request(s), as this may fail */
if (rx) {
ier_bits |= IER_RDREQE | IER_RDMAE;
desc_rx = dmaengine_prep_slave_single(p->master->dma_rx,
@@ -654,30 +644,26 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc_rx)
return -EAGAIN;
- }
-
- /* 1 stage FIFO watermarks for DMA */
- sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
- /* setup msiof transfer mode registers (32-bit words) */
- sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
-
- sh_msiof_write(p, IER, ier_bits);
-
- reinit_completion(&p->done);
-
- if (rx) {
desc_rx->callback = sh_msiof_dma_complete;
desc_rx->callback_param = p;
cookie = dmaengine_submit(desc_rx);
- if (dma_submit_error(cookie)) {
- ret = cookie;
- goto stop_ier;
- }
- dma_async_issue_pending(p->master->dma_rx);
+ if (dma_submit_error(cookie))
+ return cookie;
}
if (tx) {
+ ier_bits |= IER_TDREQE | IER_TDMAE;
+ dma_sync_single_for_device(p->master->dma_tx->device->dev,
+ p->tx_dma_addr, len, DMA_TO_DEVICE);
+ desc_tx = dmaengine_prep_slave_single(p->master->dma_tx,
+ p->tx_dma_addr, len, DMA_TO_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!desc_tx) {
+ ret = -EAGAIN;
+ goto no_dma_tx;
+ }
+
if (rx) {
/* No callback */
desc_tx->callback = NULL;
@@ -688,15 +674,30 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
cookie = dmaengine_submit(desc_tx);
if (dma_submit_error(cookie)) {
ret = cookie;
- goto stop_rx;
+ goto no_dma_tx;
}
- dma_async_issue_pending(p->master->dma_tx);
}
+ /* 1 stage FIFO watermarks for DMA */
+ sh_msiof_write(p, FCTR, FCTR_TFWM_1 | FCTR_RFWM_1);
+
+ /* setup msiof transfer mode registers (32-bit words) */
+ sh_msiof_spi_set_mode_regs(p, tx, rx, 32, len / 4);
+
+ sh_msiof_write(p, IER, ier_bits);
+
+ reinit_completion(&p->done);
+
+ /* Now start DMA */
+ if (rx)
+ dma_async_issue_pending(p->master->dma_rx);
+ if (tx)
+ dma_async_issue_pending(p->master->dma_tx);
+
ret = sh_msiof_spi_start(p, rx);
if (ret) {
dev_err(&p->pdev->dev, "failed to start hardware\n");
- goto stop_tx;
+ goto stop_dma;
}
/* wait for tx fifo to be emptied / rx fifo to be filled */
@@ -726,13 +727,12 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
stop_reset:
sh_msiof_reset_str(p);
sh_msiof_spi_stop(p, rx);
-stop_tx:
+stop_dma:
if (tx)
dmaengine_terminate_all(p->master->dma_tx);
-stop_rx:
+no_dma_tx:
if (rx)
dmaengine_terminate_all(p->master->dma_rx);
-stop_ier:
sh_msiof_write(p, IER, 0);
return ret;
}
@@ -972,20 +972,24 @@ static struct dma_chan *sh_msiof_request_dma_chan(struct device *dev,
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- chan = dma_request_channel(mask, shdma_chan_filter,
- (void *)(unsigned long)id);
+ chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
+ (void *)(unsigned long)id, dev,
+ dir == DMA_MEM_TO_DEV ? "tx" : "rx");
if (!chan) {
- dev_warn(dev, "dma_request_channel failed\n");
+ dev_warn(dev, "dma_request_slave_channel_compat failed\n");
return NULL;
}
memset(&cfg, 0, sizeof(cfg));
cfg.slave_id = id;
cfg.direction = dir;
- if (dir == DMA_MEM_TO_DEV)
+ if (dir == DMA_MEM_TO_DEV) {
cfg.dst_addr = port_addr;
- else
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ } else {
cfg.src_addr = port_addr;
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ }
ret = dmaengine_slave_config(chan, &cfg);
if (ret) {
@@ -1002,12 +1006,22 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
struct platform_device *pdev = p->pdev;
struct device *dev = &pdev->dev;
const struct sh_msiof_spi_info *info = dev_get_platdata(dev);
+ unsigned int dma_tx_id, dma_rx_id;
const struct resource *res;
struct spi_master *master;
struct device *tx_dev, *rx_dev;
- if (!info || !info->dma_tx_id || !info->dma_rx_id)
- return 0; /* The driver assumes no error */
+ if (dev->of_node) {
+ /* In the OF case we will get the slave IDs from the DT */
+ dma_tx_id = 0;
+ dma_rx_id = 0;
+ } else if (info && info->dma_tx_id && info->dma_rx_id) {
+ dma_tx_id = info->dma_tx_id;
+ dma_rx_id = info->dma_rx_id;
+ } else {
+ /* The driver assumes no error */
+ return 0;
+ }
/* The DMA engine uses the second register set, if present */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -1016,13 +1030,13 @@ static int sh_msiof_request_dma(struct sh_msiof_spi_priv *p)
master = p->master;
master->dma_tx = sh_msiof_request_dma_chan(dev, DMA_MEM_TO_DEV,
- info->dma_tx_id,
+ dma_tx_id,
res->start + TFDR);
if (!master->dma_tx)
return -ENODEV;
master->dma_rx = sh_msiof_request_dma_chan(dev, DMA_DEV_TO_MEM,
- info->dma_rx_id,
+ dma_rx_id,
res->start + RFDR);
if (!master->dma_rx)
goto free_tx_chan;
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 4d8efb16573d..79bd84f43430 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -471,7 +471,6 @@ static struct platform_driver xilinx_spi_driver = {
.remove = xilinx_spi_remove,
.driver = {
.name = XILINX_SPI_NAME,
- .owner = THIS_MODULE,
.of_match_table = xilinx_spi_of_match,
},
};
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e0531baf2782..ca935df80c88 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -848,6 +848,7 @@ out:
/**
* spi_finalize_current_transfer - report completion of a transfer
+ * @master: the master reporting completion
*
* Called by SPI drivers using the core transfer_one_message()
* implementation to notify it that the current interrupt driven