Skip to content

Commit

Permalink
Merge remote-tracking branches 'spi/topic/davinci', 'spi/topic/doc', …
Browse files Browse the repository at this point in the history
…'spi/topic/dw' and 'spi/topic/fsl' into spi-next
  • Loading branch information
Mark Brown committed Oct 3, 2014
5 parents 1fc8450 + 365a7bb + 2be01d2 + f7477c2 + a310836 commit 7020d76
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 145 deletions.
30 changes: 30 additions & 0 deletions Documentation/devicetree/bindings/spi/spi-davinci.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
Davinci SPI controller device bindings

Links on DM:
Keystone 2 - http://www.ti.com/lit/ug/sprugp2a/sprugp2a.pdf
dm644x - http://www.ti.com/lit/ug/sprue32a/sprue32a.pdf
OMAP-L138/da830 - http://www.ti.com/lit/ug/spruh77a/spruh77a.pdf

Required properties:
- #address-cells: number of cells required to define a chip select
address on the SPI bus. Should be set to 1.
Expand All @@ -24,6 +29,30 @@ Optional:
cs-gpios = <0>, <0>, <0>, <&gpio1 30 0>, <&gpio1 31 0>;
where first three are internal CS and last two are GPIO CS.

Optional properties for slave devices:
SPI slave nodes can contain the following properties.
Not all SPI Peripherals from Texas Instruments support this.
Please check SPI peripheral documentation for a device before using these.

- ti,spi-wdelay : delay between transmission of words
(SPIFMTn.WDELAY, SPIDAT1.WDEL) must be specified in number of SPI module
clock periods.

delay = WDELAY * SPI_module_clock_period + 2 * SPI_module_clock_period

Below is timing diagram which shows functional meaning of
"ti,spi-wdelay" parameter.

+-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+
SPI_CLK | | | | | | | | | | | | | | | |
+----------+ +-+ +-+ +-+ +-+ +---------------------------+ +-+ +-+ +-

SPI_SOMI/SIMO+-----------------+ +-----------
+----------+ word1 +---------------------------+word2
+-----------------+ +-----------
WDELAY
<-------------------------->

Example of a NOR flash slave device (n25q032) connected to DaVinci
SPI controller device over the SPI bus.

Expand All @@ -43,6 +72,7 @@ spi0:spi@20BF0000 {
compatible = "st,m25p32";
spi-max-frequency = <25000000>;
reg = <0>;
ti,spi-wdelay = <8>;

partition@0 {
label = "u-boot-spl";
Expand Down
6 changes: 3 additions & 3 deletions Documentation/spi/spi-summary
Original file line number Diff line number Diff line change
Expand Up @@ -601,13 +601,13 @@ THANKS TO
Contributors to Linux-SPI discussions include (in alphabetical order,
by last name):

Mark Brown
David Brownell
Russell King
Grant Likely
Dmitry Pervushin
Stephen Street
Mark Underwood
Andrew Victor
Vitaly Wool
Grant Likely
Mark Brown
Linus Walleij
Vitaly Wool
2 changes: 1 addition & 1 deletion drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ config SPI_DW_PCI
depends on SPI_DESIGNWARE && PCI

config SPI_DW_MID_DMA
bool "DMA support for DW SPI controller on Intel Moorestown platform"
bool "DMA support for DW SPI controller on Intel MID platform"
depends on SPI_DW_PCI && INTEL_MID_DMAC

config SPI_DW_MMIO
Expand Down
55 changes: 48 additions & 7 deletions drivers/spi/spi-davinci.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@

/* SPIDAT1 (upper 16 bit defines) */
#define SPIDAT1_CSHOLD_MASK BIT(12)
#define SPIDAT1_WDEL BIT(10)

/* SPIGCR1 */
#define SPIGCR1_CLKMOD_MASK BIT(1)
Expand Down Expand Up @@ -213,6 +214,7 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
{
struct davinci_spi *dspi;
struct davinci_spi_platform_data *pdata;
struct davinci_spi_config *spicfg = spi->controller_data;
u8 chip_sel = spi->chip_select;
u16 spidat1 = CS_DEFAULT;
bool gpio_chipsel = false;
Expand All @@ -227,6 +229,10 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
gpio = spi->cs_gpio;
}

/* program delay transfers if tx_delay is non zero */
if (spicfg->wdelay)
spidat1 |= SPIDAT1_WDEL;

/*
* Board specific chip select logic decides the polarity and cs
* line for the controller
Expand All @@ -241,9 +247,9 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value)
spidat1 |= SPIDAT1_CSHOLD_MASK;
spidat1 &= ~(0x1 << chip_sel);
}

iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
}

iowrite16(spidat1, dspi->base + SPIDAT1 + 2);
}

/**
Expand Down Expand Up @@ -289,7 +295,7 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
int prescale;

dspi = spi_master_get_devdata(spi->master);
spicfg = (struct davinci_spi_config *)spi->controller_data;
spicfg = spi->controller_data;
if (!spicfg)
spicfg = &davinci_spi_default_cfg;

Expand Down Expand Up @@ -336,6 +342,14 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
if (!(spi->mode & SPI_CPHA))
spifmt |= SPIFMT_PHASE_MASK;

/*
* Assume wdelay is used only on SPI peripherals that has this field
* in SPIFMTn register and when it's configured from board file or DT.
*/
if (spicfg->wdelay)
spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
& SPIFMT_WDELAY_MASK);

/*
* Version 1 hardware supports two basic SPI modes:
* - Standard SPI mode uses 4 pins, with chipselect
Expand All @@ -353,9 +367,6 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,

u32 delay = 0;

spifmt |= ((spicfg->wdelay << SPIFMT_WDELAY_SHIFT)
& SPIFMT_WDELAY_MASK);

if (spicfg->odd_parity)
spifmt |= SPIFMT_ODD_PARITY_MASK;

Expand Down Expand Up @@ -387,6 +398,26 @@ static int davinci_spi_setup_transfer(struct spi_device *spi,
return 0;
}

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;
u32 prop;

if (spicfg == NULL && np) {
spicfg = kzalloc(sizeof(*spicfg), GFP_KERNEL);
if (!spicfg)
return -ENOMEM;
*spicfg = davinci_spi_default_cfg;
/* override with dt configured values */
if (!of_property_read_u32(np, "ti,spi-wdelay", &prop))
spicfg->wdelay = (u8)prop;
spi->controller_data = spicfg;
}

return 0;
}

/**
* davinci_spi_setup - This functions will set default transfer method
* @spi: spi device on which data transfer to be done
Expand Down Expand Up @@ -437,7 +468,16 @@ static int davinci_spi_setup(struct spi_device *spi)
else
clear_io_bits(dspi->base + SPIGCR1, SPIGCR1_LOOPBACK_MASK);

return retval;
return davinci_spi_of_setup(spi);
}

static void davinci_spi_cleanup(struct spi_device *spi)
{
struct davinci_spi_config *spicfg = spi->controller_data;

spi->controller_data = NULL;
if (spi->dev.of_node)
kfree(spicfg);
}

static int davinci_spi_check_error(struct davinci_spi *dspi, int int_status)
Expand Down Expand Up @@ -951,6 +991,7 @@ static int davinci_spi_probe(struct platform_device *pdev)
master->num_chipselect = pdata->num_chipselect;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16);
master->setup = davinci_spi_setup;
master->cleanup = davinci_spi_cleanup;

dspi->bitbang.chipselect = davinci_spi_chipselect;
dspi->bitbang.setup_transfer = davinci_spi_setup_transfer;
Expand Down
65 changes: 34 additions & 31 deletions drivers/spi/spi-dw-mid.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Special handling for DW core on Intel MID platform
*
* Copyright (c) 2009, Intel Corporation.
* Copyright (c) 2009, 2014 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
Expand All @@ -11,10 +11,6 @@
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <linux/dma-mapping.h>
Expand All @@ -39,22 +35,25 @@ static bool mid_spi_dma_chan_filter(struct dma_chan *chan, void *param)
{
struct dw_spi *dws = param;

return dws->dmac && (&dws->dmac->dev == chan->device->dev);
return dws->dma_dev == chan->device->dev;
}

static int mid_spi_dma_init(struct dw_spi *dws)
{
struct mid_dma *dw_dma = dws->dma_priv;
struct pci_dev *dma_dev;
struct intel_mid_dma_slave *rxs, *txs;
dma_cap_mask_t mask;

/*
* Get pci device for DMA controller, currently it could only
* be the DMA controller of either Moorestown or Medfield
* be the DMA controller of Medfield
*/
dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0813, NULL);
if (!dws->dmac)
dws->dmac = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
dma_dev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x0827, NULL);
if (!dma_dev)
return -ENODEV;

dws->dma_dev = &dma_dev->dev;

dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
Expand Down Expand Up @@ -83,13 +82,18 @@ static int mid_spi_dma_init(struct dw_spi *dws)
free_rxchan:
dma_release_channel(dws->rxchan);
err_exit:
return -1;

return -EBUSY;
}

static void mid_spi_dma_exit(struct dw_spi *dws)
{
if (!dws->dma_inited)
return;

dmaengine_terminate_all(dws->txchan);
dma_release_channel(dws->txchan);

dmaengine_terminate_all(dws->rxchan);
dma_release_channel(dws->rxchan);
}

Expand All @@ -109,8 +113,7 @@ static void dw_spi_dma_done(void *arg)

static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
{
struct dma_async_tx_descriptor *txdesc = NULL, *rxdesc = NULL;
struct dma_chan *txchan, *rxchan;
struct dma_async_tx_descriptor *txdesc, *rxdesc;
struct dma_slave_config txconf, rxconf;
u16 dma_ctrl = 0;

Expand All @@ -120,37 +123,34 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
dw_writew(dws, DW_SPI_DMARDLR, 0xf);
dw_writew(dws, DW_SPI_DMATDLR, 0x10);
if (dws->tx_dma)
dma_ctrl |= 0x2;
dma_ctrl |= SPI_DMA_TDMAE;
if (dws->rx_dma)
dma_ctrl |= 0x1;
dma_ctrl |= SPI_DMA_RDMAE;
dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
spi_enable_chip(dws, 1);
}

dws->dma_chan_done = 0;
txchan = dws->txchan;
rxchan = dws->rxchan;

/* 2. Prepare the TX dma transfer */
txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = dws->dma_addr;
txconf.dst_maxburst = LNW_DMA_MSIZE_16;
txconf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
txconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
txconf.dst_addr_width = dws->dma_width;
txconf.device_fc = false;

txchan->device->device_control(txchan, DMA_SLAVE_CONFIG,
(unsigned long) &txconf);
dmaengine_slave_config(dws->txchan, &txconf);

memset(&dws->tx_sgl, 0, sizeof(dws->tx_sgl));
dws->tx_sgl.dma_address = dws->tx_dma;
dws->tx_sgl.length = dws->len;

txdesc = dmaengine_prep_slave_sg(txchan,
txdesc = dmaengine_prep_slave_sg(dws->txchan,
&dws->tx_sgl,
1,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT);
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
txdesc->callback = dw_spi_dma_done;
txdesc->callback_param = dws;

Expand All @@ -159,27 +159,30 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
rxconf.src_addr = dws->dma_addr;
rxconf.src_maxburst = LNW_DMA_MSIZE_16;
rxconf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
rxconf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
rxconf.src_addr_width = dws->dma_width;
rxconf.device_fc = false;

rxchan->device->device_control(rxchan, DMA_SLAVE_CONFIG,
(unsigned long) &rxconf);
dmaengine_slave_config(dws->rxchan, &rxconf);

memset(&dws->rx_sgl, 0, sizeof(dws->rx_sgl));
dws->rx_sgl.dma_address = dws->rx_dma;
dws->rx_sgl.length = dws->len;

rxdesc = dmaengine_prep_slave_sg(rxchan,
rxdesc = dmaengine_prep_slave_sg(dws->rxchan,
&dws->rx_sgl,
1,
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
rxdesc->callback = dw_spi_dma_done;
rxdesc->callback_param = dws;

/* rx must be started before tx due to spi instinct */
rxdesc->tx_submit(rxdesc);
txdesc->tx_submit(txdesc);
dmaengine_submit(rxdesc);
dma_async_issue_pending(dws->rxchan);

dmaengine_submit(txdesc);
dma_async_issue_pending(dws->txchan);

return 0;
}

Expand All @@ -190,7 +193,7 @@ static struct dw_spi_dma_ops mid_dma_ops = {
};
#endif

/* Some specific info for SPI0 controller on Moorestown */
/* Some specific info for SPI0 controller on Intel MID */

/* HW info for MRST CLk Control Unit, one 32b reg */
#define MRST_SPI_CLK_BASE 100000000 /* 100m */
Expand Down
Loading

0 comments on commit 7020d76

Please sign in to comment.