Commit b9e2c097 authored by Mark Brown's avatar Mark Brown
Browse files

Merge remote-tracking branches 'spi/topic/pxa', 'spi/topic/rb4xx',...

Merge remote-tracking branches 'spi/topic/pxa', 'spi/topic/rb4xx', 'spi/topic/rspi', 'spi/topic/s3c64xx' and 'spi/topic/sh-msiof' into spi-next
Loading
Loading
Loading
Loading
+7 −8
Original line number Original line Diff line number Diff line
@@ -395,16 +395,9 @@ config SPI_PPC4xx
	help
	help
	  This selects a driver for the PPC4xx SPI Controller.
	  This selects a driver for the PPC4xx SPI Controller.


config SPI_PXA2XX_PXADMA
	bool "PXA2xx SSP legacy PXA DMA API support"
	depends on SPI_PXA2XX && ARCH_PXA
	help
	  Enable PXA private legacy DMA API support. Note that this is
	  deprecated in favor of generic DMA engine API.

config SPI_PXA2XX_DMA
config SPI_PXA2XX_DMA
	def_bool y
	def_bool y
	depends on SPI_PXA2XX && !SPI_PXA2XX_PXADMA
	depends on SPI_PXA2XX


config SPI_PXA2XX
config SPI_PXA2XX
	tristate "PXA2xx SSP SPI master"
	tristate "PXA2xx SSP SPI master"
@@ -430,6 +423,12 @@ config SPI_ROCKCHIP
	  The main usecase of this controller is to use spi flash as boot
	  The main usecase of this controller is to use spi flash as boot
	  device.
	  device.


config SPI_RB4XX
	tristate "Mikrotik RB4XX SPI master"
	depends on SPI_MASTER && ATH79
	help
	  SPI controller driver for the Mikrotik RB4xx series boards.

config SPI_RSPI
config SPI_RSPI
	tristate "Renesas RSPI/QSPI controller"
	tristate "Renesas RSPI/QSPI controller"
	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+1 −1
Original line number Original line Diff line number Diff line
@@ -60,12 +60,12 @@ obj-$(CONFIG_SPI_ORION) += spi-orion.o
obj-$(CONFIG_SPI_PL022)			+= spi-pl022.o
obj-$(CONFIG_SPI_PL022)			+= spi-pl022.o
obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o
obj-$(CONFIG_SPI_PPC4xx)		+= spi-ppc4xx.o
spi-pxa2xx-platform-objs		:= spi-pxa2xx.o
spi-pxa2xx-platform-objs		:= spi-pxa2xx.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA)	+= spi-pxa2xx-pxadma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)	+= spi-pxa2xx-dma.o
spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA)	+= spi-pxa2xx-dma.o
obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX)		+= spi-pxa2xx-platform.o
obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_PXA2XX_PCI)		+= spi-pxa2xx-pci.o
obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
obj-$(CONFIG_SPI_QUP)			+= spi-qup.o
obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
obj-$(CONFIG_SPI_ROCKCHIP)		+= spi-rockchip.o
obj-$(CONFIG_SPI_RB4XX)			+= spi-rb4xx.o
obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o
obj-$(CONFIG_SPI_RSPI)			+= spi-rspi.o
obj-$(CONFIG_SPI_S3C24XX)		+= spi-s3c24xx-hw.o
obj-$(CONFIG_SPI_S3C24XX)		+= spi-s3c24xx-hw.o
spi-s3c24xx-hw-y			:= spi-s3c24xx.o
spi-s3c24xx-hw-y			:= spi-s3c24xx.o
+4 −4
Original line number Original line Diff line number Diff line
@@ -62,7 +62,7 @@ static struct pxa_spi_info spi_info_configs[] = {
		.max_clk_rate = 3686400,
		.max_clk_rate = 3686400,
	},
	},
	[PORT_BYT] = {
	[PORT_BYT] = {
		.type = LPSS_SSP,
		.type = LPSS_BYT_SSP,
		.port_id = 0,
		.port_id = 0,
		.num_chipselect = 1,
		.num_chipselect = 1,
		.max_clk_rate = 50000000,
		.max_clk_rate = 50000000,
@@ -70,7 +70,7 @@ static struct pxa_spi_info spi_info_configs[] = {
		.rx_param = &byt_rx_param,
		.rx_param = &byt_rx_param,
	},
	},
	[PORT_BSW0] = {
	[PORT_BSW0] = {
		.type = LPSS_SSP,
		.type = LPSS_BYT_SSP,
		.port_id = 0,
		.port_id = 0,
		.num_chipselect = 1,
		.num_chipselect = 1,
		.max_clk_rate = 50000000,
		.max_clk_rate = 50000000,
@@ -78,7 +78,7 @@ static struct pxa_spi_info spi_info_configs[] = {
		.rx_param = &bsw0_rx_param,
		.rx_param = &bsw0_rx_param,
	},
	},
	[PORT_BSW1] = {
	[PORT_BSW1] = {
		.type = LPSS_SSP,
		.type = LPSS_BYT_SSP,
		.port_id = 1,
		.port_id = 1,
		.num_chipselect = 1,
		.num_chipselect = 1,
		.max_clk_rate = 50000000,
		.max_clk_rate = 50000000,
@@ -86,7 +86,7 @@ static struct pxa_spi_info spi_info_configs[] = {
		.rx_param = &bsw1_rx_param,
		.rx_param = &bsw1_rx_param,
	},
	},
	[PORT_BSW2] = {
	[PORT_BSW2] = {
		.type = LPSS_SSP,
		.type = LPSS_BYT_SSP,
		.port_id = 2,
		.port_id = 2,
		.num_chipselect = 1,
		.num_chipselect = 1,
		.max_clk_rate = 50000000,
		.max_clk_rate = 50000000,

drivers/spi/spi-pxa2xx-pxadma.c

deleted100644 → 0
+0 −487
Original line number Original line Diff line number Diff line
/*
 * PXA2xx SPI private DMA support.
 *
 * Copyright (C) 2005 Stephen Street / StreetFire Sound Labs
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
#include <linux/pxa2xx_ssp.h>
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>

#include <mach/dma.h>
#include "spi-pxa2xx.h"

#define DMA_INT_MASK		(DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
#define RESET_DMA_CHANNEL	(DCSR_NODESC | DMA_INT_MASK)

bool pxa2xx_spi_dma_is_possible(size_t len)
{
	/* Try to map dma buffer and do a dma transfer if successful, but
	 * only if the length is non-zero and less than MAX_DMA_LEN.
	 *
	 * Zero-length non-descriptor DMA is illegal on PXA2xx; force use
	 * of PIO instead.  Care is needed above because the transfer may
	 * have have been passed with buffers that are already dma mapped.
	 * A zero-length transfer in PIO mode will not try to write/read
	 * to/from the buffers
	 *
	 * REVISIT large transfers are exactly where we most want to be
	 * using DMA.  If this happens much, split those transfers into
	 * multiple DMA segments rather than forcing PIO.
	 */
	return len > 0 && len <= MAX_DMA_LEN;
}

int pxa2xx_spi_map_dma_buffers(struct driver_data *drv_data)
{
	struct spi_message *msg = drv_data->cur_msg;
	struct device *dev = &msg->spi->dev;

	if (!drv_data->cur_chip->enable_dma)
		return 0;

	if (msg->is_dma_mapped)
		return  drv_data->rx_dma && drv_data->tx_dma;

	if (!IS_DMA_ALIGNED(drv_data->rx) || !IS_DMA_ALIGNED(drv_data->tx))
		return 0;

	/* Modify setup if rx buffer is null */
	if (drv_data->rx == NULL) {
		*drv_data->null_dma_buf = 0;
		drv_data->rx = drv_data->null_dma_buf;
		drv_data->rx_map_len = 4;
	} else
		drv_data->rx_map_len = drv_data->len;


	/* Modify setup if tx buffer is null */
	if (drv_data->tx == NULL) {
		*drv_data->null_dma_buf = 0;
		drv_data->tx = drv_data->null_dma_buf;
		drv_data->tx_map_len = 4;
	} else
		drv_data->tx_map_len = drv_data->len;

	/* Stream map the tx buffer. Always do DMA_TO_DEVICE first
	 * so we flush the cache *before* invalidating it, in case
	 * the tx and rx buffers overlap.
	 */
	drv_data->tx_dma = dma_map_single(dev, drv_data->tx,
					drv_data->tx_map_len, DMA_TO_DEVICE);
	if (dma_mapping_error(dev, drv_data->tx_dma))
		return 0;

	/* Stream map the rx buffer */
	drv_data->rx_dma = dma_map_single(dev, drv_data->rx,
					drv_data->rx_map_len, DMA_FROM_DEVICE);
	if (dma_mapping_error(dev, drv_data->rx_dma)) {
		dma_unmap_single(dev, drv_data->tx_dma,
					drv_data->tx_map_len, DMA_TO_DEVICE);
		return 0;
	}

	return 1;
}

static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
{
	struct device *dev;

	if (!drv_data->dma_mapped)
		return;

	if (!drv_data->cur_msg->is_dma_mapped) {
		dev = &drv_data->cur_msg->spi->dev;
		dma_unmap_single(dev, drv_data->rx_dma,
					drv_data->rx_map_len, DMA_FROM_DEVICE);
		dma_unmap_single(dev, drv_data->tx_dma,
					drv_data->tx_map_len, DMA_TO_DEVICE);
	}

	drv_data->dma_mapped = 0;
}

static int wait_ssp_rx_stall(struct driver_data *drv_data)
{
	unsigned long limit = loops_per_jiffy << 1;

	while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit)
		cpu_relax();

	return limit;
}

static int wait_dma_channel_stop(int channel)
{
	unsigned long limit = loops_per_jiffy << 1;

	while (!(DCSR(channel) & DCSR_STOPSTATE) && --limit)
		cpu_relax();

	return limit;
}

static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
				      const char *msg)
{
	/* Stop and reset */
	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
	write_SSSR_CS(drv_data, drv_data->clear_sr);
	pxa2xx_spi_write(drv_data, SSCR1,
			 pxa2xx_spi_read(drv_data, SSCR1)
			 & ~drv_data->dma_cr1);
	if (!pxa25x_ssp_comp(drv_data))
		pxa2xx_spi_write(drv_data, SSTO, 0);
	pxa2xx_spi_flush(drv_data);
	pxa2xx_spi_write(drv_data, SSCR0,
			 pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);

	pxa2xx_spi_unmap_dma_buffers(drv_data);

	dev_err(&drv_data->pdev->dev, "%s\n", msg);

	drv_data->cur_msg->state = ERROR_STATE;
	tasklet_schedule(&drv_data->pump_transfers);
}

static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data)
{
	struct spi_message *msg = drv_data->cur_msg;

	/* Clear and disable interrupts on SSP and DMA channels*/
	pxa2xx_spi_write(drv_data, SSCR1,
			 pxa2xx_spi_read(drv_data, SSCR1)
			 & ~drv_data->dma_cr1);
	write_SSSR_CS(drv_data, drv_data->clear_sr);
	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;

	if (wait_dma_channel_stop(drv_data->rx_channel) == 0)
		dev_err(&drv_data->pdev->dev,
			"dma_handler: dma rx channel stop failed\n");

	if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
		dev_err(&drv_data->pdev->dev,
			"dma_transfer: ssp rx stall failed\n");

	pxa2xx_spi_unmap_dma_buffers(drv_data);

	/* update the buffer pointer for the amount completed in dma */
	drv_data->rx += drv_data->len -
			(DCMD(drv_data->rx_channel) & DCMD_LENGTH);

	/* read trailing data from fifo, it does not matter how many
	 * bytes are in the fifo just read until buffer is full
	 * or fifo is empty, which ever occurs first */
	drv_data->read(drv_data);

	/* return count of what was actually read */
	msg->actual_length += drv_data->len -
				(drv_data->rx_end - drv_data->rx);

	/* Transfer delays and chip select release are
	 * handled in pump_transfers or giveback
	 */

	/* Move to next transfer */
	msg->state = pxa2xx_spi_next_transfer(drv_data);

	/* Schedule transfer tasklet */
	tasklet_schedule(&drv_data->pump_transfers);
}

void pxa2xx_spi_dma_handler(int channel, void *data)
{
	struct driver_data *drv_data = data;
	u32 irq_status = DCSR(channel) & DMA_INT_MASK;

	if (irq_status & DCSR_BUSERR) {

		if (channel == drv_data->tx_channel)
			pxa2xx_spi_dma_error_stop(drv_data,
				"dma_handler: bad bus address on tx channel");
		else
			pxa2xx_spi_dma_error_stop(drv_data,
				"dma_handler: bad bus address on rx channel");
		return;
	}

	/* PXA255x_SSP has no timeout interrupt, wait for tailing bytes */
	if ((channel == drv_data->tx_channel)
		&& (irq_status & DCSR_ENDINTR)
		&& (drv_data->ssp_type == PXA25x_SSP)) {

		/* Wait for rx to stall */
		if (wait_ssp_rx_stall(drv_data) == 0)
			dev_err(&drv_data->pdev->dev,
				"dma_handler: ssp rx stall failed\n");

		/* finish this transfer, start the next */
		pxa2xx_spi_dma_transfer_complete(drv_data);
	}
}

irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{
	u32 irq_status;

	irq_status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
	if (irq_status & SSSR_ROR) {
		pxa2xx_spi_dma_error_stop(drv_data,
					  "dma_transfer: fifo overrun");
		return IRQ_HANDLED;
	}

	/* Check for false positive timeout */
	if ((irq_status & SSSR_TINT)
		&& (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
		pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT);
		return IRQ_HANDLED;
	}

	if (irq_status & SSSR_TINT || drv_data->rx == drv_data->rx_end) {

		/* Clear and disable timeout interrupt, do the rest in
		 * dma_transfer_complete */
		if (!pxa25x_ssp_comp(drv_data))
			pxa2xx_spi_write(drv_data, SSTO, 0);

		/* finish this transfer, start the next */
		pxa2xx_spi_dma_transfer_complete(drv_data);

		return IRQ_HANDLED;
	}

	/* Opps problem detected */
	return IRQ_NONE;
}

int pxa2xx_spi_dma_prepare(struct driver_data *drv_data, u32 dma_burst)
{
	u32 dma_width;

	switch (drv_data->n_bytes) {
	case 1:
		dma_width = DCMD_WIDTH1;
		break;
	case 2:
		dma_width = DCMD_WIDTH2;
		break;
	default:
		dma_width = DCMD_WIDTH4;
		break;
	}

	/* Setup rx DMA Channel */
	DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
	DSADR(drv_data->rx_channel) = drv_data->ssdr_physical;
	DTADR(drv_data->rx_channel) = drv_data->rx_dma;
	if (drv_data->rx == drv_data->null_dma_buf)
		/* No target address increment */
		DCMD(drv_data->rx_channel) = DCMD_FLOWSRC
						| dma_width
						| dma_burst
						| drv_data->len;
	else
		DCMD(drv_data->rx_channel) = DCMD_INCTRGADDR
						| DCMD_FLOWSRC
						| dma_width
						| dma_burst
						| drv_data->len;

	/* Setup tx DMA Channel */
	DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
	DSADR(drv_data->tx_channel) = drv_data->tx_dma;
	DTADR(drv_data->tx_channel) = drv_data->ssdr_physical;
	if (drv_data->tx == drv_data->null_dma_buf)
		/* No source address increment */
		DCMD(drv_data->tx_channel) = DCMD_FLOWTRG
						| dma_width
						| dma_burst
						| drv_data->len;
	else
		DCMD(drv_data->tx_channel) = DCMD_INCSRCADDR
						| DCMD_FLOWTRG
						| dma_width
						| dma_burst
						| drv_data->len;

	/* Enable dma end irqs on SSP to detect end of transfer */
	if (drv_data->ssp_type == PXA25x_SSP)
		DCMD(drv_data->tx_channel) |= DCMD_ENDIRQEN;

	return 0;
}

void pxa2xx_spi_dma_start(struct driver_data *drv_data)
{
	DCSR(drv_data->rx_channel) |= DCSR_RUN;
	DCSR(drv_data->tx_channel) |= DCSR_RUN;
}

int pxa2xx_spi_dma_setup(struct driver_data *drv_data)
{
	struct device *dev = &drv_data->pdev->dev;
	struct ssp_device *ssp = drv_data->ssp;

	/* Get two DMA channels	(rx and tx) */
	drv_data->rx_channel = pxa_request_dma("pxa2xx_spi_ssp_rx",
						DMA_PRIO_HIGH,
						pxa2xx_spi_dma_handler,
						drv_data);
	if (drv_data->rx_channel < 0) {
		dev_err(dev, "problem (%d) requesting rx channel\n",
			drv_data->rx_channel);
		return -ENODEV;
	}
	drv_data->tx_channel = pxa_request_dma("pxa2xx_spi_ssp_tx",
						DMA_PRIO_MEDIUM,
						pxa2xx_spi_dma_handler,
						drv_data);
	if (drv_data->tx_channel < 0) {
		dev_err(dev, "problem (%d) requesting tx channel\n",
			drv_data->tx_channel);
		pxa_free_dma(drv_data->rx_channel);
		return -ENODEV;
	}

	DRCMR(ssp->drcmr_rx) = DRCMR_MAPVLD | drv_data->rx_channel;
	DRCMR(ssp->drcmr_tx) = DRCMR_MAPVLD | drv_data->tx_channel;

	return 0;
}

void pxa2xx_spi_dma_release(struct driver_data *drv_data)
{
	struct ssp_device *ssp = drv_data->ssp;

	DRCMR(ssp->drcmr_rx) = 0;
	DRCMR(ssp->drcmr_tx) = 0;

	if (drv_data->tx_channel != 0)
		pxa_free_dma(drv_data->tx_channel);
	if (drv_data->rx_channel != 0)
		pxa_free_dma(drv_data->rx_channel);
}

void pxa2xx_spi_dma_resume(struct driver_data *drv_data)
{
	if (drv_data->rx_channel != -1)
		DRCMR(drv_data->ssp->drcmr_rx) =
			DRCMR_MAPVLD | drv_data->rx_channel;
	if (drv_data->tx_channel != -1)
		DRCMR(drv_data->ssp->drcmr_tx) =
			DRCMR_MAPVLD | drv_data->tx_channel;
}

int pxa2xx_spi_set_dma_burst_and_threshold(struct chip_data *chip,
					   struct spi_device *spi,
					   u8 bits_per_word, u32 *burst_code,
					   u32 *threshold)
{
	struct pxa2xx_spi_chip *chip_info =
			(struct pxa2xx_spi_chip *)spi->controller_data;
	int bytes_per_word;
	int burst_bytes;
	int thresh_words;
	int req_burst_size;
	int retval = 0;

	/* Set the threshold (in registers) to equal the same amount of data
	 * as represented by burst size (in bytes).  The computation below
	 * is (burst_size rounded up to nearest 8 byte, word or long word)
	 * divided by (bytes/register); the tx threshold is the inverse of
	 * the rx, so that there will always be enough data in the rx fifo
	 * to satisfy a burst, and there will always be enough space in the
	 * tx fifo to accept a burst (a tx burst will overwrite the fifo if
	 * there is not enough space), there must always remain enough empty
	 * space in the rx fifo for any data loaded to the tx fifo.
	 * Whenever burst_size (in bytes) equals bits/word, the fifo threshold
	 * will be 8, or half the fifo;
	 * The threshold can only be set to 2, 4 or 8, but not 16, because
	 * to burst 16 to the tx fifo, the fifo would have to be empty;
	 * however, the minimum fifo trigger level is 1, and the tx will
	 * request service when the fifo is at this level, with only 15 spaces.
	 */

	/* find bytes/word */
	if (bits_per_word <= 8)
		bytes_per_word = 1;
	else if (bits_per_word <= 16)
		bytes_per_word = 2;
	else
		bytes_per_word = 4;

	/* use struct pxa2xx_spi_chip->dma_burst_size if available */
	if (chip_info)
		req_burst_size = chip_info->dma_burst_size;
	else {
		switch (chip->dma_burst_size) {
		default:
			/* if the default burst size is not set,
			 * do it now */
			chip->dma_burst_size = DCMD_BURST8;
		case DCMD_BURST8:
			req_burst_size = 8;
			break;
		case DCMD_BURST16:
			req_burst_size = 16;
			break;
		case DCMD_BURST32:
			req_burst_size = 32;
			break;
		}
	}
	if (req_burst_size <= 8) {
		*burst_code = DCMD_BURST8;
		burst_bytes = 8;
	} else if (req_burst_size <= 16) {
		if (bytes_per_word == 1) {
			/* don't burst more than 1/2 the fifo */
			*burst_code = DCMD_BURST8;
			burst_bytes = 8;
			retval = 1;
		} else {
			*burst_code = DCMD_BURST16;
			burst_bytes = 16;
		}
	} else {
		if (bytes_per_word == 1) {
			/* don't burst more than 1/2 the fifo */
			*burst_code = DCMD_BURST8;
			burst_bytes = 8;
			retval = 1;
		} else if (bytes_per_word == 2) {
			/* don't burst more than 1/2 the fifo */
			*burst_code = DCMD_BURST16;
			burst_bytes = 16;
			retval = 1;
		} else {
			*burst_code = DCMD_BURST32;
			burst_bytes = 32;
		}
	}

	thresh_words = burst_bytes / bytes_per_word;

	/* thresh_words will be between 2 and 8 */
	*threshold = (SSCR1_RxTresh(thresh_words) & SSCR1_RFT)
			| (SSCR1_TxTresh(16-thresh_words) & SSCR1_TFT);

	return retval;
}
+95 −64
Original line number Original line Diff line number Diff line
@@ -60,21 +60,60 @@ MODULE_ALIAS("platform:pxa2xx-spi");
				| QUARK_X1000_SSCR1_TFT		\
				| QUARK_X1000_SSCR1_TFT		\
				| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
				| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)


#define LPSS_RX_THRESH_DFLT	64
#define LPSS_TX_LOTHRESH_DFLT	160
#define LPSS_TX_HITHRESH_DFLT	224

/* Offset from drv_data->lpss_base */
#define GENERAL_REG		0x08
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
#define SSP_REG			0x0c
#define SPI_CS_CONTROL		0x18
#define SPI_CS_CONTROL_SW_MODE	BIT(0)
#define SPI_CS_CONTROL_SW_MODE	BIT(0)
#define SPI_CS_CONTROL_CS_HIGH	BIT(1)
#define SPI_CS_CONTROL_CS_HIGH	BIT(1)


struct lpss_config {
	/* LPSS offset from drv_data->ioaddr */
	unsigned offset;
	/* Register offsets from drv_data->lpss_base or -1 */
	int reg_general;
	int reg_ssp;
	int reg_cs_ctrl;
	/* FIFO thresholds */
	u32 rx_threshold;
	u32 tx_threshold_lo;
	u32 tx_threshold_hi;
};

/* Keep these sorted with enum pxa_ssp_type */
static const struct lpss_config lpss_platforms[] = {
	{	/* LPSS_LPT_SSP */
		.offset = 0x800,
		.reg_general = 0x08,
		.reg_ssp = 0x0c,
		.reg_cs_ctrl = 0x18,
		.rx_threshold = 64,
		.tx_threshold_lo = 160,
		.tx_threshold_hi = 224,
	},
	{	/* LPSS_BYT_SSP */
		.offset = 0x400,
		.reg_general = 0x08,
		.reg_ssp = 0x0c,
		.reg_cs_ctrl = 0x18,
		.rx_threshold = 64,
		.tx_threshold_lo = 160,
		.tx_threshold_hi = 224,
	},
};

static inline const struct lpss_config
*lpss_get_config(const struct driver_data *drv_data)
{
	return &lpss_platforms[drv_data->ssp_type - LPSS_LPT_SSP];
}

static bool is_lpss_ssp(const struct driver_data *drv_data)
static bool is_lpss_ssp(const struct driver_data *drv_data)
{
{
	return drv_data->ssp_type == LPSS_SSP;
	switch (drv_data->ssp_type) {
	case LPSS_LPT_SSP:
	case LPSS_BYT_SSP:
		return true;
	default:
		return false;
	}
}
}


static bool is_quark_x1000_ssp(const struct driver_data *drv_data)
static bool is_quark_x1000_ssp(const struct driver_data *drv_data)
@@ -192,63 +231,43 @@ static void __lpss_ssp_write_priv(struct driver_data *drv_data,
 */
 */
static void lpss_ssp_setup(struct driver_data *drv_data)
static void lpss_ssp_setup(struct driver_data *drv_data)
{
{
	unsigned offset = 0x400;
	const struct lpss_config *config;
	u32 value, orig;
	u32 value;

	/*
	 * Perform auto-detection of the LPSS SSP private registers. They
	 * can be either at 1k or 2k offset from the base address.
	 */
	orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);

	/* Test SPI_CS_CONTROL_SW_MODE bit enabling */
	value = orig | SPI_CS_CONTROL_SW_MODE;
	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
	if (value != (orig | SPI_CS_CONTROL_SW_MODE)) {
		offset = 0x800;
		goto detection_done;
	}

	orig = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);

	/* Test SPI_CS_CONTROL_SW_MODE bit disabling */
	value = orig & ~SPI_CS_CONTROL_SW_MODE;
	writel(value, drv_data->ioaddr + offset + SPI_CS_CONTROL);
	value = readl(drv_data->ioaddr + offset + SPI_CS_CONTROL);
	if (value != (orig & ~SPI_CS_CONTROL_SW_MODE)) {
		offset = 0x800;
		goto detection_done;
	}


detection_done:
	config = lpss_get_config(drv_data);
	/* Now set the LPSS base */
	drv_data->lpss_base = drv_data->ioaddr + config->offset;
	drv_data->lpss_base = drv_data->ioaddr + offset;


	/* Enable software chip select control */
	/* Enable software chip select control */
	value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
	value = SPI_CS_CONTROL_SW_MODE | SPI_CS_CONTROL_CS_HIGH;
	__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
	__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);


	/* Enable multiblock DMA transfers */
	/* Enable multiblock DMA transfers */
	if (drv_data->master_info->enable_dma) {
	if (drv_data->master_info->enable_dma) {
		__lpss_ssp_write_priv(drv_data, SSP_REG, 1);
		__lpss_ssp_write_priv(drv_data, config->reg_ssp, 1);


		value = __lpss_ssp_read_priv(drv_data, GENERAL_REG);
		if (config->reg_general >= 0) {
			value = __lpss_ssp_read_priv(drv_data,
						     config->reg_general);
			value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
			value |= GENERAL_REG_RXTO_HOLDOFF_DISABLE;
		__lpss_ssp_write_priv(drv_data, GENERAL_REG, value);
			__lpss_ssp_write_priv(drv_data,
					      config->reg_general, value);
		}
	}
	}
}
}


static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
{
{
	const struct lpss_config *config;
	u32 value;
	u32 value;


	value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
	config = lpss_get_config(drv_data);

	value = __lpss_ssp_read_priv(drv_data, config->reg_cs_ctrl);
	if (enable)
	if (enable)
		value &= ~SPI_CS_CONTROL_CS_HIGH;
		value &= ~SPI_CS_CONTROL_CS_HIGH;
	else
	else
		value |= SPI_CS_CONTROL_CS_HIGH;
		value |= SPI_CS_CONTROL_CS_HIGH;
	__lpss_ssp_write_priv(drv_data, SPI_CS_CONTROL, value);
	__lpss_ssp_write_priv(drv_data, config->reg_cs_ctrl, value);
}
}


static void cs_assert(struct driver_data *drv_data)
static void cs_assert(struct driver_data *drv_data)
@@ -1075,6 +1094,7 @@ static int setup(struct spi_device *spi)
{
{
	struct pxa2xx_spi_chip *chip_info = NULL;
	struct pxa2xx_spi_chip *chip_info = NULL;
	struct chip_data *chip;
	struct chip_data *chip;
	const struct lpss_config *config;
	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
	struct driver_data *drv_data = spi_master_get_devdata(spi->master);
	unsigned int clk_div;
	unsigned int clk_div;
	uint tx_thres, tx_hi_thres, rx_thres;
	uint tx_thres, tx_hi_thres, rx_thres;
@@ -1085,10 +1105,12 @@ static int setup(struct spi_device *spi)
		tx_hi_thres = 0;
		tx_hi_thres = 0;
		rx_thres = RX_THRESH_QUARK_X1000_DFLT;
		rx_thres = RX_THRESH_QUARK_X1000_DFLT;
		break;
		break;
	case LPSS_SSP:
	case LPSS_LPT_SSP:
		tx_thres = LPSS_TX_LOTHRESH_DFLT;
	case LPSS_BYT_SSP:
		tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
		config = lpss_get_config(drv_data);
		rx_thres = LPSS_RX_THRESH_DFLT;
		tx_thres = config->tx_threshold_lo;
		tx_hi_thres = config->tx_threshold_hi;
		rx_thres = config->rx_threshold;
		break;
		break;
	default:
	default:
		tx_thres = TX_THRESH_DFLT;
		tx_thres = TX_THRESH_DFLT;
@@ -1242,6 +1264,18 @@ static void cleanup(struct spi_device *spi)
}
}


#ifdef CONFIG_ACPI
#ifdef CONFIG_ACPI

static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
	{ "INT33C0", LPSS_LPT_SSP },
	{ "INT33C1", LPSS_LPT_SSP },
	{ "INT3430", LPSS_LPT_SSP },
	{ "INT3431", LPSS_LPT_SSP },
	{ "80860F0E", LPSS_BYT_SSP },
	{ "8086228E", LPSS_BYT_SSP },
	{ },
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);

static struct pxa2xx_spi_master *
static struct pxa2xx_spi_master *
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
{
{
@@ -1249,12 +1283,19 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
	struct acpi_device *adev;
	struct acpi_device *adev;
	struct ssp_device *ssp;
	struct ssp_device *ssp;
	struct resource *res;
	struct resource *res;
	int devid;
	const struct acpi_device_id *id;
	int devid, type;


	if (!ACPI_HANDLE(&pdev->dev) ||
	if (!ACPI_HANDLE(&pdev->dev) ||
	    acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
	    acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev))
		return NULL;
		return NULL;


	id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
	if (id)
		type = (int)id->driver_data;
	else
		return NULL;

	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
	if (!pdata)
	if (!pdata)
		return NULL;
		return NULL;
@@ -1272,7 +1313,7 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)


	ssp->clk = devm_clk_get(&pdev->dev, NULL);
	ssp->clk = devm_clk_get(&pdev->dev, NULL);
	ssp->irq = platform_get_irq(pdev, 0);
	ssp->irq = platform_get_irq(pdev, 0);
	ssp->type = LPSS_SSP;
	ssp->type = type;
	ssp->pdev = pdev;
	ssp->pdev = pdev;


	ssp->port_id = -1;
	ssp->port_id = -1;
@@ -1285,16 +1326,6 @@ pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
	return pdata;
	return pdata;
}
}


static struct acpi_device_id pxa2xx_spi_acpi_match[] = {
	{ "INT33C0", 0 },
	{ "INT33C1", 0 },
	{ "INT3430", 0 },
	{ "INT3431", 0 },
	{ "80860F0E", 0 },
	{ "8086228E", 0 },
	{ },
};
MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
#else
#else
static inline struct pxa2xx_spi_master *
static inline struct pxa2xx_spi_master *
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
pxa2xx_spi_acpi_get_pdata(struct platform_device *pdev)
Loading