Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7020d769 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'spi/topic/davinci', 'spi/topic/doc',...

Merge remote-tracking branches 'spi/topic/davinci', 'spi/topic/doc', 'spi/topic/dw' and 'spi/topic/fsl' into spi-next
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
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.
@@ -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.

@@ -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";
+3 −3
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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
+48 −7
Original line number Diff line number Diff line
@@ -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)
@@ -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;
@@ -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
@@ -241,10 +247,10 @@ 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);
}
}

/**
 * davinci_spi_get_prescale - Calculates the correct prescale value
@@ -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;

@@ -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
@@ -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;

@@ -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
@@ -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)
@@ -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;
+34 −31
Original line number Diff line number Diff line
/*
 * 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,
@@ -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>
@@ -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);
@@ -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);
}

@@ -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;

@@ -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;

@@ -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;
}

@@ -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 */
Loading