Merge remote-tracking branches 'spi/topic/atmel', 'spi/topic/bcm63xx', 'spi/topic/cadence' and 'spi/topic/davinci' into spi-next
This commit is contained in:
commit
2536374352
33
Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt
Normal file
33
Documentation/devicetree/bindings/spi/spi-bcm63xx-hsspi.txt
Normal file
@ -0,0 +1,33 @@
|
||||
Binding for Broadcom BCM6328 High Speed SPI controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must contain of "brcm,bcm6328-hsspi".
|
||||
- reg: Base address and size of the controllers memory area.
|
||||
- interrupts: Interrupt for the SPI block.
|
||||
- clocks: phandles of the SPI clock and the PLL clock.
|
||||
- clock-names: must be "hsspi", "pll".
|
||||
- #address-cells: <1>, as required by generic SPI binding.
|
||||
- #size-cells: <0>, also as required by generic SPI binding.
|
||||
|
||||
Optional properties:
|
||||
- num-cs: some controllers have less than 8 cs signals. Defaults to 8
|
||||
if absent.
|
||||
|
||||
Child nodes as per the generic SPI binding.
|
||||
|
||||
Example:
|
||||
|
||||
spi@10001000 {
|
||||
compatible = "brcm,bcm6328-hsspi";
|
||||
reg = <0x10001000 0x600>;
|
||||
|
||||
interrupts = <29>;
|
||||
|
||||
clocks = <&clkctl 9>, <&hsspi_pll>;
|
||||
clock-names = "hsspi", "pll";
|
||||
|
||||
num-cs = <2>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
33
Documentation/devicetree/bindings/spi/spi-bcm63xx.txt
Normal file
33
Documentation/devicetree/bindings/spi/spi-bcm63xx.txt
Normal file
@ -0,0 +1,33 @@
|
||||
Binding for Broadcom BCM6348/BCM6358 SPI controller
|
||||
|
||||
Required properties:
|
||||
- compatible: must contain one of "brcm,bcm6348-spi", "brcm,bcm6358-spi".
|
||||
- reg: Base address and size of the controllers memory area.
|
||||
- interrupts: Interrupt for the SPI block.
|
||||
- clocks: phandle of the SPI clock.
|
||||
- clock-names: has to be "spi".
|
||||
- #address-cells: <1>, as required by generic SPI binding.
|
||||
- #size-cells: <0>, also as required by generic SPI binding.
|
||||
|
||||
Optional properties:
|
||||
- num-cs: some controllers have less than 8 cs signals. Defaults to 8
|
||||
if absent.
|
||||
|
||||
Child nodes as per the generic SPI binding.
|
||||
|
||||
Example:
|
||||
|
||||
spi@10000800 {
|
||||
compatible = "brcm,bcm6368-spi", "brcm,bcm6358-spi";
|
||||
reg = <0x10000800 0x70c>;
|
||||
|
||||
interrupts = <1>;
|
||||
|
||||
clocks = <&clkctl 9>;
|
||||
clock-names = "spi";
|
||||
|
||||
num-cs = <5>;
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
};
|
@ -1464,6 +1464,25 @@ static int atmel_spi_gpio_cs(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void atmel_spi_init(struct atmel_spi *as)
|
||||
{
|
||||
spi_writel(as, CR, SPI_BIT(SWRST));
|
||||
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
|
||||
if (as->caps.has_wdrbt) {
|
||||
spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
|
||||
| SPI_BIT(MSTR));
|
||||
} else {
|
||||
spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
|
||||
}
|
||||
|
||||
if (as->use_pdc)
|
||||
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
|
||||
spi_writel(as, CR, SPI_BIT(SPIEN));
|
||||
|
||||
if (as->fifo_size)
|
||||
spi_writel(as, CR, SPI_BIT(FIFOEN));
|
||||
}
|
||||
|
||||
static int atmel_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *regs;
|
||||
@ -1572,26 +1591,14 @@ static int atmel_spi_probe(struct platform_device *pdev)
|
||||
|
||||
as->spi_clk = clk_get_rate(clk);
|
||||
|
||||
spi_writel(as, CR, SPI_BIT(SWRST));
|
||||
spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
|
||||
if (as->caps.has_wdrbt) {
|
||||
spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS)
|
||||
| SPI_BIT(MSTR));
|
||||
} else {
|
||||
spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
|
||||
}
|
||||
|
||||
if (as->use_pdc)
|
||||
spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
|
||||
spi_writel(as, CR, SPI_BIT(SPIEN));
|
||||
|
||||
as->fifo_size = 0;
|
||||
if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size",
|
||||
&as->fifo_size)) {
|
||||
dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size);
|
||||
spi_writel(as, CR, SPI_BIT(FIFOEN));
|
||||
}
|
||||
|
||||
atmel_spi_init(as);
|
||||
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_runtime_set_active(&pdev->dev);
|
||||
@ -1695,8 +1702,17 @@ static int atmel_spi_suspend(struct device *dev)
|
||||
static int atmel_spi_resume(struct device *dev)
|
||||
{
|
||||
struct spi_master *master = dev_get_drvdata(dev);
|
||||
struct atmel_spi *as = spi_master_get_devdata(master);
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(as->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
atmel_spi_init(as);
|
||||
|
||||
clk_disable_unprepare(as->clk);
|
||||
|
||||
if (!pm_runtime_suspended(dev)) {
|
||||
ret = atmel_spi_runtime_resume(dev);
|
||||
if (ret)
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#define HSSPI_GLOBAL_CTRL_REG 0x0
|
||||
#define GLOBAL_CTRL_CS_POLARITY_SHIFT 0
|
||||
@ -91,6 +92,7 @@
|
||||
|
||||
#define HSSPI_MAX_SYNC_CLOCK 30000000
|
||||
|
||||
#define HSSPI_SPI_MAX_CS 8
|
||||
#define HSSPI_BUS_NUM 1 /* 0 is legacy SPI */
|
||||
|
||||
struct bcm63xx_hsspi {
|
||||
@ -332,7 +334,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *clk;
|
||||
int irq, ret;
|
||||
u32 reg, rate;
|
||||
u32 reg, rate, num_cs = HSSPI_SPI_MAX_CS;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
@ -351,8 +353,16 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(clk);
|
||||
|
||||
rate = clk_get_rate(clk);
|
||||
if (!rate)
|
||||
return -EINVAL;
|
||||
if (!rate) {
|
||||
struct clk *pll_clk = devm_clk_get(dev, "pll");
|
||||
|
||||
if (IS_ERR(pll_clk))
|
||||
return PTR_ERR(pll_clk);
|
||||
|
||||
rate = clk_get_rate(pll_clk);
|
||||
if (!rate)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret)
|
||||
@ -374,8 +384,17 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev)
|
||||
mutex_init(&bs->bus_mutex);
|
||||
init_completion(&bs->done);
|
||||
|
||||
master->bus_num = HSSPI_BUS_NUM;
|
||||
master->num_chipselect = 8;
|
||||
master->dev.of_node = dev->of_node;
|
||||
if (!dev->of_node)
|
||||
master->bus_num = HSSPI_BUS_NUM;
|
||||
|
||||
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
|
||||
if (num_cs > 8) {
|
||||
dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
|
||||
num_cs);
|
||||
num_cs = HSSPI_SPI_MAX_CS;
|
||||
}
|
||||
master->num_chipselect = num_cs;
|
||||
master->setup = bcm63xx_hsspi_setup;
|
||||
master->transfer_one_message = bcm63xx_hsspi_transfer_one;
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH |
|
||||
@ -461,10 +480,16 @@ static int bcm63xx_hsspi_resume(struct device *dev)
|
||||
static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend,
|
||||
bcm63xx_hsspi_resume);
|
||||
|
||||
static const struct of_device_id bcm63xx_hsspi_of_match[] = {
|
||||
{ .compatible = "brcm,bcm6328-hsspi", },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct platform_driver bcm63xx_hsspi_driver = {
|
||||
.driver = {
|
||||
.name = "bcm63xx-hsspi",
|
||||
.pm = &bcm63xx_hsspi_pm_ops,
|
||||
.of_match_table = bcm63xx_hsspi_of_match,
|
||||
},
|
||||
.probe = bcm63xx_hsspi_probe,
|
||||
.remove = bcm63xx_hsspi_remove,
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/completion.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/* BCM 6338/6348 SPI core */
|
||||
#define SPI_6348_RSET_SIZE 64
|
||||
@ -428,6 +429,13 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static size_t bcm63xx_spi_max_length(struct spi_device *spi)
|
||||
{
|
||||
struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
|
||||
|
||||
return bs->fifo_size;
|
||||
}
|
||||
|
||||
static const unsigned long bcm6348_spi_reg_offsets[] = {
|
||||
[SPI_CMD] = SPI_6348_CMD,
|
||||
[SPI_INT_STATUS] = SPI_6348_INT_STATUS,
|
||||
@ -477,21 +485,48 @@ static const struct platform_device_id bcm63xx_spi_dev_match[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static const struct of_device_id bcm63xx_spi_of_match[] = {
|
||||
{ .compatible = "brcm,bcm6348-spi", .data = &bcm6348_spi_reg_offsets },
|
||||
{ .compatible = "brcm,bcm6358-spi", .data = &bcm6358_spi_reg_offsets },
|
||||
{ },
|
||||
};
|
||||
|
||||
static int bcm63xx_spi_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *r;
|
||||
const unsigned long *bcm63xx_spireg;
|
||||
struct device *dev = &pdev->dev;
|
||||
int irq;
|
||||
int irq, bus_num;
|
||||
struct spi_master *master;
|
||||
struct clk *clk;
|
||||
struct bcm63xx_spi *bs;
|
||||
int ret;
|
||||
u32 num_cs = BCM63XX_SPI_MAX_CS;
|
||||
|
||||
if (!pdev->id_entry->driver_data)
|
||||
if (dev->of_node) {
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(bcm63xx_spi_of_match, dev->of_node);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
bcm63xx_spireg = match->data;
|
||||
|
||||
of_property_read_u32(dev->of_node, "num-cs", &num_cs);
|
||||
if (num_cs > BCM63XX_SPI_MAX_CS) {
|
||||
dev_warn(dev, "unsupported number of cs (%i), reducing to 8\n",
|
||||
num_cs);
|
||||
num_cs = BCM63XX_SPI_MAX_CS;
|
||||
}
|
||||
|
||||
bus_num = -1;
|
||||
} else if (pdev->id_entry->driver_data) {
|
||||
const struct platform_device_id *match = pdev->id_entry;
|
||||
|
||||
bcm63xx_spireg = (const unsigned long *)match->driver_data;
|
||||
bus_num = BCM63XX_SPI_BUS_NUM;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
|
||||
bcm63xx_spireg = (const unsigned long *)pdev->id_entry->driver_data;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
@ -536,11 +571,14 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
master->bus_num = BCM63XX_SPI_BUS_NUM;
|
||||
master->num_chipselect = BCM63XX_SPI_MAX_CS;
|
||||
master->dev.of_node = dev->of_node;
|
||||
master->bus_num = bus_num;
|
||||
master->num_chipselect = num_cs;
|
||||
master->transfer_one_message = bcm63xx_spi_transfer_one;
|
||||
master->mode_bits = MODEBITS;
|
||||
master->bits_per_word_mask = SPI_BPW_MASK(8);
|
||||
master->max_transfer_size = bcm63xx_spi_max_length;
|
||||
master->max_message_size = bcm63xx_spi_max_length;
|
||||
master->auto_runtime_pm = true;
|
||||
bs->msg_type_shift = bs->reg_offsets[SPI_MSG_TYPE_SHIFT];
|
||||
bs->msg_ctl_width = bs->reg_offsets[SPI_MSG_CTL_WIDTH];
|
||||
@ -624,6 +662,7 @@ static struct platform_driver bcm63xx_spi_driver = {
|
||||
.driver = {
|
||||
.name = "bcm63xx-spi",
|
||||
.pm = &bcm63xx_spi_pm_ops,
|
||||
.of_match_table = bcm63xx_spi_of_match,
|
||||
},
|
||||
.id_table = bcm63xx_spi_dev_match,
|
||||
.probe = bcm63xx_spi_probe,
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
@ -127,6 +128,10 @@ struct cdns_spi {
|
||||
u32 is_decoded_cs;
|
||||
};
|
||||
|
||||
struct cdns_spi_device_data {
|
||||
bool gpio_requested;
|
||||
};
|
||||
|
||||
/* Macros for the SPI controller read/write */
|
||||
static inline u32 cdns_spi_read(struct cdns_spi *xspi, u32 offset)
|
||||
{
|
||||
@ -456,6 +461,64 @@ static int cdns_unprepare_transfer_hardware(struct spi_master *master)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_spi_setup(struct spi_device *spi)
|
||||
{
|
||||
|
||||
int ret = -EINVAL;
|
||||
struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi);
|
||||
|
||||
/* this is a pin managed by the controller, leave it alone */
|
||||
if (spi->cs_gpio == -ENOENT)
|
||||
return 0;
|
||||
|
||||
/* this seems to be the first time we're here */
|
||||
if (!cdns_spi_data) {
|
||||
cdns_spi_data = kzalloc(sizeof(*cdns_spi_data), GFP_KERNEL);
|
||||
if (!cdns_spi_data)
|
||||
return -ENOMEM;
|
||||
cdns_spi_data->gpio_requested = false;
|
||||
spi_set_ctldata(spi, cdns_spi_data);
|
||||
}
|
||||
|
||||
/* if we haven't done so, grab the gpio */
|
||||
if (!cdns_spi_data->gpio_requested && gpio_is_valid(spi->cs_gpio)) {
|
||||
ret = gpio_request_one(spi->cs_gpio,
|
||||
(spi->mode & SPI_CS_HIGH) ?
|
||||
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH,
|
||||
dev_name(&spi->dev));
|
||||
if (ret)
|
||||
dev_err(&spi->dev, "can't request chipselect gpio %d\n",
|
||||
spi->cs_gpio);
|
||||
else
|
||||
cdns_spi_data->gpio_requested = true;
|
||||
} else {
|
||||
if (gpio_is_valid(spi->cs_gpio)) {
|
||||
int mode = ((spi->mode & SPI_CS_HIGH) ?
|
||||
GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH);
|
||||
|
||||
ret = gpio_direction_output(spi->cs_gpio, mode);
|
||||
if (ret)
|
||||
dev_err(&spi->dev, "chipselect gpio %d setup failed (%d)\n",
|
||||
spi->cs_gpio, ret);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cdns_spi_cleanup(struct spi_device *spi)
|
||||
{
|
||||
struct cdns_spi_device_data *cdns_spi_data = spi_get_ctldata(spi);
|
||||
|
||||
if (cdns_spi_data) {
|
||||
if (cdns_spi_data->gpio_requested)
|
||||
gpio_free(spi->cs_gpio);
|
||||
kfree(cdns_spi_data);
|
||||
spi_set_ctldata(spi, NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* cdns_spi_probe - Probe method for the SPI driver
|
||||
* @pdev: Pointer to the platform_device structure
|
||||
@ -555,6 +618,8 @@ static int cdns_spi_probe(struct platform_device *pdev)
|
||||
master->transfer_one = cdns_transfer_one;
|
||||
master->unprepare_transfer_hardware = cdns_unprepare_transfer_hardware;
|
||||
master->set_cs = cdns_spi_chipselect;
|
||||
master->setup = cdns_spi_setup;
|
||||
master->cleanup = cdns_spi_cleanup;
|
||||
master->auto_runtime_pm = true;
|
||||
master->mode_bits = SPI_CPOL | SPI_CPHA;
|
||||
|
||||
|
@ -109,6 +109,8 @@
|
||||
#define SPIDEF 0x4c
|
||||
#define SPIFMT0 0x50
|
||||
|
||||
#define DMA_MIN_BYTES 16
|
||||
|
||||
/* SPI Controller driver's private data. */
|
||||
struct davinci_spi {
|
||||
struct spi_bitbang bitbang;
|
||||
@ -389,6 +391,7 @@ static int davinci_spi_of_setup(struct spi_device *spi)
|
||||
{
|
||||
struct davinci_spi_config *spicfg = spi->controller_data;
|
||||
struct device_node *np = spi->dev.of_node;
|
||||
struct davinci_spi *dspi = spi_master_get_devdata(spi->master);
|
||||
u32 prop;
|
||||
|
||||
if (spicfg == NULL && np) {
|
||||
@ -400,6 +403,9 @@ static int davinci_spi_of_setup(struct spi_device *spi)
|
||||
if (!of_property_read_u32(np, "ti,spi-wdelay", &prop))
|
||||
spicfg->wdelay = (u8)prop;
|
||||
spi->controller_data = spicfg;
|
||||
|
||||
if (dspi->dma_rx && dspi->dma_tx)
|
||||
spicfg->io_type = SPI_IO_TYPE_DMA;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -467,6 +473,22 @@ static void davinci_spi_cleanup(struct spi_device *spi)
|
||||
kfree(spicfg);
|
||||
}
|
||||
|
||||
static bool davinci_spi_can_dma(struct spi_master *master,
|
||||
struct spi_device *spi,
|
||||
struct spi_transfer *xfer)
|
||||
{
|
||||
struct davinci_spi_config *spicfg = spi->controller_data;
|
||||
bool can_dma = false;
|
||||
|
||||
if (spicfg)
|
||||
can_dma = (spicfg->io_type == SPI_IO_TYPE_DMA) &&
|
||||
(xfer->len >= DMA_MIN_BYTES) &&
|
||||
!is_vmalloc_addr(xfer->rx_buf) &&
|
||||
!is_vmalloc_addr(xfer->tx_buf);
|
||||
|
||||
return can_dma;
|
||||
}
|
||||
|
||||
static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
|
||||
{
|
||||
struct device *sdev = dspi->bitbang.master->dev.parent;
|
||||
@ -581,8 +603,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
struct davinci_spi_config *spicfg;
|
||||
struct davinci_spi_platform_data *pdata;
|
||||
unsigned uninitialized_var(rx_buf_count);
|
||||
void *dummy_buf = NULL;
|
||||
struct scatterlist sg_rx, sg_tx;
|
||||
|
||||
dspi = spi_master_get_devdata(spi->master);
|
||||
pdata = &dspi->pdata;
|
||||
@ -605,10 +625,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
|
||||
reinit_completion(&dspi->done);
|
||||
|
||||
if (spicfg->io_type == SPI_IO_TYPE_INTR)
|
||||
set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
|
||||
|
||||
if (spicfg->io_type != SPI_IO_TYPE_DMA) {
|
||||
if (!davinci_spi_can_dma(spi->master, spi, t)) {
|
||||
if (spicfg->io_type != SPI_IO_TYPE_POLL)
|
||||
set_io_bits(dspi->base + SPIINT, SPIINT_MASKINT);
|
||||
/* start the transfer */
|
||||
dspi->wcount--;
|
||||
tx_data = dspi->get_tx(dspi);
|
||||
@ -630,51 +649,28 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
};
|
||||
struct dma_async_tx_descriptor *rxdesc;
|
||||
struct dma_async_tx_descriptor *txdesc;
|
||||
void *buf;
|
||||
|
||||
dummy_buf = kzalloc(t->len, GFP_KERNEL);
|
||||
if (!dummy_buf)
|
||||
goto err_alloc_dummy_buf;
|
||||
|
||||
dmaengine_slave_config(dspi->dma_rx, &dma_rx_conf);
|
||||
dmaengine_slave_config(dspi->dma_tx, &dma_tx_conf);
|
||||
|
||||
sg_init_table(&sg_rx, 1);
|
||||
if (!t->rx_buf)
|
||||
buf = dummy_buf;
|
||||
else
|
||||
buf = t->rx_buf;
|
||||
t->rx_dma = dma_map_single(&spi->dev, buf,
|
||||
t->len, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(&spi->dev, !t->rx_dma)) {
|
||||
ret = -EFAULT;
|
||||
goto err_rx_map;
|
||||
}
|
||||
sg_dma_address(&sg_rx) = t->rx_dma;
|
||||
sg_dma_len(&sg_rx) = t->len;
|
||||
|
||||
sg_init_table(&sg_tx, 1);
|
||||
if (!t->tx_buf)
|
||||
buf = dummy_buf;
|
||||
else
|
||||
buf = (void *)t->tx_buf;
|
||||
t->tx_dma = dma_map_single(&spi->dev, buf,
|
||||
t->len, DMA_TO_DEVICE);
|
||||
if (dma_mapping_error(&spi->dev, t->tx_dma)) {
|
||||
ret = -EFAULT;
|
||||
goto err_tx_map;
|
||||
}
|
||||
sg_dma_address(&sg_tx) = t->tx_dma;
|
||||
sg_dma_len(&sg_tx) = t->len;
|
||||
|
||||
rxdesc = dmaengine_prep_slave_sg(dspi->dma_rx,
|
||||
&sg_rx, 1, DMA_DEV_TO_MEM,
|
||||
t->rx_sg.sgl, t->rx_sg.nents, DMA_DEV_TO_MEM,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!rxdesc)
|
||||
goto err_desc;
|
||||
|
||||
if (!t->tx_buf) {
|
||||
/* To avoid errors when doing rx-only transfers with
|
||||
* many SG entries (> 20), use the rx buffer as the
|
||||
* dummy tx buffer so that dma reloads are done at the
|
||||
* same time for rx and tx.
|
||||
*/
|
||||
t->tx_sg.sgl = t->rx_sg.sgl;
|
||||
t->tx_sg.nents = t->rx_sg.nents;
|
||||
}
|
||||
|
||||
txdesc = dmaengine_prep_slave_sg(dspi->dma_tx,
|
||||
&sg_tx, 1, DMA_MEM_TO_DEV,
|
||||
t->tx_sg.sgl, t->tx_sg.nents, DMA_MEM_TO_DEV,
|
||||
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
|
||||
if (!txdesc)
|
||||
goto err_desc;
|
||||
@ -710,16 +706,9 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
}
|
||||
|
||||
clear_io_bits(dspi->base + SPIINT, SPIINT_MASKALL);
|
||||
if (spicfg->io_type == SPI_IO_TYPE_DMA) {
|
||||
if (davinci_spi_can_dma(spi->master, spi, t))
|
||||
clear_io_bits(dspi->base + SPIINT, SPIINT_DMA_REQ_EN);
|
||||
|
||||
dma_unmap_single(&spi->dev, t->rx_dma,
|
||||
t->len, DMA_FROM_DEVICE);
|
||||
dma_unmap_single(&spi->dev, t->tx_dma,
|
||||
t->len, DMA_TO_DEVICE);
|
||||
kfree(dummy_buf);
|
||||
}
|
||||
|
||||
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_SPIENA_MASK);
|
||||
set_io_bits(dspi->base + SPIGCR1, SPIGCR1_POWERDOWN_MASK);
|
||||
|
||||
@ -742,12 +731,6 @@ static int davinci_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
|
||||
return t->len;
|
||||
|
||||
err_desc:
|
||||
dma_unmap_single(&spi->dev, t->tx_dma, t->len, DMA_TO_DEVICE);
|
||||
err_tx_map:
|
||||
dma_unmap_single(&spi->dev, t->rx_dma, t->len, DMA_FROM_DEVICE);
|
||||
err_rx_map:
|
||||
kfree(dummy_buf);
|
||||
err_alloc_dummy_buf:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -988,8 +971,10 @@ static int davinci_spi_probe(struct platform_device *pdev)
|
||||
master->bus_num = pdev->id;
|
||||
master->num_chipselect = pdata->num_chipselect;
|
||||
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
|
||||
master->flags = SPI_MASTER_MUST_RX;
|
||||
master->setup = davinci_spi_setup;
|
||||
master->cleanup = davinci_spi_cleanup;
|
||||
master->can_dma = davinci_spi_can_dma;
|
||||
|
||||
dspi->bitbang.chipselect = davinci_spi_chipselect;
|
||||
dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
|
||||
|
Loading…
Reference in New Issue
Block a user