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

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

Merge remote-tracking branches 'spi/topic/res', 'spi/topic/rockchip',...

Merge remote-tracking branches 'spi/topic/res', 'spi/topic/rockchip', 'spi/topic/sh', 'spi/topic/ti-qspi' and 'spi/topic/xilinx' into spi-next
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@ Required Properties:
    "rockchip,rk3066-spi" for rk3066.
    "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
    "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
    "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
- reg: physical base address of the controller and length of memory mapped
       region.
- interrupts: The interrupt number to the cpu. The interrupt specifier format
+22 −0
Original line number Diff line number Diff line
Xilinx SPI controller Device Tree Bindings
-------------------------------------------------

Required properties:
- compatible		: Should be "xlnx,xps-spi-2.00.a" or "xlnx,xps-spi-2.00.b"
- reg			: Physical base address and size of SPI registers map.
- interrupts		: Property with a value describing the interrupt
			  number.
- interrupt-parent	: Must be core interrupt controller

Optional properties:
- xlnx,num-ss-bits	: Number of chip selects used.

Example:
	axi_quad_spi@41e00000 {
			compatible = "xlnx,xps-spi-2.00.a";
			interrupt-parent = <&intc>;
			interrupts = <0 31 1>;
			reg = <0x41e00000 0x10000>;
			xlnx,num-ss-bits = <0x1>;
	};
+3 −3
Original line number Diff line number Diff line
@@ -487,7 +487,7 @@ config SPI_RB4XX

config SPI_RSPI
	tristate "Renesas RSPI/QSPI controller"
	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
	help
	  SPI driver for Renesas RSPI and QSPI blocks.

@@ -537,7 +537,7 @@ config SPI_SC18IS602
config SPI_SH_MSIOF
	tristate "SuperH MSIOF SPI controller"
	depends on HAVE_CLK && HAS_DMA
	depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
	help
	  SPI driver for SuperH and SH Mobile MSIOF blocks.

@@ -556,7 +556,7 @@ config SPI_SH_SCI

config SPI_SH_HSPI
	tristate "SuperH HSPI controller"
	depends on ARCH_SHMOBILE || COMPILE_TEST
	depends on ARCH_RENESAS || COMPILE_TEST
	help
	  SPI driver for SuperH HSPI blocks.

+35 −21
Original line number Diff line number Diff line
@@ -13,20 +13,14 @@
 *
 */

#include <linux/init.h>
#include <linux/module.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/scatterlist.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/dmaengine.h>
#include <linux/scatterlist.h>

#define DRIVER_NAME "rockchip-spi"

@@ -179,7 +173,7 @@ struct rockchip_spi {
	u8 tmode;
	u8 bpw;
	u8 n_bytes;
	u8 rsd_nsecs;
	u32 rsd_nsecs;
	unsigned len;
	u32 speed;

@@ -192,8 +186,6 @@ struct rockchip_spi {
	/* protect state */
	spinlock_t lock;

	struct completion xfer_completion;

	u32 use_dma;
	struct sg_table tx_sg;
	struct sg_table rx_sg;
@@ -265,7 +257,10 @@ static inline u32 rx_max(struct rockchip_spi *rs)
static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
{
	u32 ser;
	struct rockchip_spi *rs = spi_master_get_devdata(spi->master);
	struct spi_master *master = spi->master;
	struct rockchip_spi *rs = spi_master_get_devdata(master);

	pm_runtime_get_sync(rs->dev);

	ser = readl_relaxed(rs->regs + ROCKCHIP_SPI_SER) & SER_MASK;

@@ -290,6 +285,8 @@ static void rockchip_spi_set_cs(struct spi_device *spi, bool enable)
		ser &= ~(1 << spi->chip_select);

	writel_relaxed(ser, rs->regs + ROCKCHIP_SPI_SER);

	pm_runtime_put_sync(rs->dev);
}

static int rockchip_spi_prepare_message(struct spi_master *master,
@@ -319,12 +316,12 @@ static void rockchip_spi_handle_err(struct spi_master *master,
	 */
	if (rs->use_dma) {
		if (rs->state & RXBUSY) {
			dmaengine_terminate_all(rs->dma_rx.ch);
			dmaengine_terminate_async(rs->dma_rx.ch);
			flush_fifo(rs);
		}

		if (rs->state & TXBUSY)
			dmaengine_terminate_all(rs->dma_tx.ch);
			dmaengine_terminate_async(rs->dma_tx.ch);
	}

	spin_unlock_irqrestore(&rs->lock, flags);
@@ -433,7 +430,7 @@ static void rockchip_spi_dma_txcb(void *data)
	spin_unlock_irqrestore(&rs->lock, flags);
}

static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
static int rockchip_spi_prepare_dma(struct rockchip_spi *rs)
{
	unsigned long flags;
	struct dma_slave_config rxconf, txconf;
@@ -456,6 +453,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
				rs->dma_rx.ch,
				rs->rx_sg.sgl, rs->rx_sg.nents,
				rs->dma_rx.direction, DMA_PREP_INTERRUPT);
		if (!rxdesc)
			return -EINVAL;

		rxdesc->callback = rockchip_spi_dma_rxcb;
		rxdesc->callback_param = rs;
@@ -473,6 +472,11 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
				rs->dma_tx.ch,
				rs->tx_sg.sgl, rs->tx_sg.nents,
				rs->dma_tx.direction, DMA_PREP_INTERRUPT);
		if (!txdesc) {
			if (rxdesc)
				dmaengine_terminate_sync(rs->dma_rx.ch);
			return -EINVAL;
		}

		txdesc->callback = rockchip_spi_dma_txcb;
		txdesc->callback_param = rs;
@@ -494,6 +498,8 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
		dmaengine_submit(txdesc);
		dma_async_issue_pending(rs->dma_tx.ch);
	}

	return 0;
}

static void rockchip_spi_config(struct rockchip_spi *rs)
@@ -503,7 +509,8 @@ static void rockchip_spi_config(struct rockchip_spi *rs)
	int rsd = 0;

	u32 cr0 = (CR0_BHT_8BIT << CR0_BHT_OFFSET)
		| (CR0_SSD_ONE << CR0_SSD_OFFSET);
		| (CR0_SSD_ONE << CR0_SSD_OFFSET)
		| (CR0_EM_BIG << CR0_EM_OFFSET);

	cr0 |= (rs->n_bytes << CR0_DFS_OFFSET);
	cr0 |= ((rs->mode & 0x3) << CR0_SCPH_OFFSET);
@@ -606,12 +613,12 @@ static int rockchip_spi_transfer_one(
	if (rs->use_dma) {
		if (rs->tmode == CR0_XFM_RO) {
			/* rx: dma must be prepared first */
			rockchip_spi_prepare_dma(rs);
			ret = rockchip_spi_prepare_dma(rs);
			spi_enable_chip(rs, 1);
		} else {
			/* tx or tr: spi must be enabled first */
			spi_enable_chip(rs, 1);
			rockchip_spi_prepare_dma(rs);
			ret = rockchip_spi_prepare_dma(rs);
		}
	} else {
		spi_enable_chip(rs, 1);
@@ -717,8 +724,14 @@ static int rockchip_spi_probe(struct platform_device *pdev)
	master->handle_err = rockchip_spi_handle_err;

	rs->dma_tx.ch = dma_request_slave_channel(rs->dev, "tx");
	if (!rs->dma_tx.ch)
	if (IS_ERR_OR_NULL(rs->dma_tx.ch)) {
		/* Check tx to see if we need defer probing driver */
		if (PTR_ERR(rs->dma_tx.ch) == -EPROBE_DEFER) {
			ret = -EPROBE_DEFER;
			goto err_get_fifo_len;
		}
		dev_warn(rs->dev, "Failed to request TX DMA channel\n");
	}

	rs->dma_rx.ch = dma_request_slave_channel(rs->dev, "rx");
	if (!rs->dma_rx.ch) {
@@ -871,6 +884,7 @@ static const struct of_device_id rockchip_spi_dt_match[] = {
	{ .compatible = "rockchip,rk3066-spi", },
	{ .compatible = "rockchip,rk3188-spi", },
	{ .compatible = "rockchip,rk3288-spi", },
	{ .compatible = "rockchip,rk3399-spi", },
	{ },
};
MODULE_DEVICE_TABLE(of, rockchip_spi_dt_match);
+110 −29
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/mfd/syscon.h>
#include <linux/regmap.h>

#include <linux/spi/spi.h>

@@ -44,8 +46,9 @@ struct ti_qspi {

	struct spi_master	*master;
	void __iomem            *base;
	void __iomem            *ctrl_base;
	void __iomem            *mmap_base;
	struct regmap		*ctrl_base;
	unsigned int		ctrl_reg;
	struct clk		*fclk;
	struct device           *dev;

@@ -55,7 +58,7 @@ struct ti_qspi {
	u32 cmd;
	u32 dc;

	bool ctrl_mod;
	bool mmap_enabled;
};

#define QSPI_PID			(0x0)
@@ -65,11 +68,8 @@ struct ti_qspi {
#define QSPI_SPI_CMD_REG		(0x48)
#define QSPI_SPI_STATUS_REG		(0x4c)
#define QSPI_SPI_DATA_REG		(0x50)
#define QSPI_SPI_SETUP0_REG		(0x54)
#define QSPI_SPI_SETUP_REG(n)		((0x54 + 4 * n))
#define QSPI_SPI_SWITCH_REG		(0x64)
#define QSPI_SPI_SETUP1_REG		(0x58)
#define QSPI_SPI_SETUP2_REG		(0x5c)
#define QSPI_SPI_SETUP3_REG		(0x60)
#define QSPI_SPI_DATA_REG_1		(0x68)
#define QSPI_SPI_DATA_REG_2		(0x6c)
#define QSPI_SPI_DATA_REG_3		(0x70)
@@ -109,6 +109,17 @@ struct ti_qspi {

#define QSPI_AUTOSUSPEND_TIMEOUT         2000

#define MEM_CS_EN(n)			((n + 1) << 8)
#define MEM_CS_MASK			(7 << 8)

#define MM_SWITCH			0x1

#define QSPI_SETUP_RD_NORMAL		(0x0 << 12)
#define QSPI_SETUP_RD_DUAL		(0x1 << 12)
#define QSPI_SETUP_RD_QUAD		(0x3 << 12)
#define QSPI_SETUP_ADDR_SHIFT		8
#define QSPI_SETUP_DUMMY_SHIFT		10

static inline unsigned long ti_qspi_read(struct ti_qspi *qspi,
		unsigned long reg)
{
@@ -366,6 +377,72 @@ static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t)
	return 0;
}

static void ti_qspi_enable_memory_map(struct spi_device *spi)
{
	struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);

	ti_qspi_write(qspi, MM_SWITCH, QSPI_SPI_SWITCH_REG);
	if (qspi->ctrl_base) {
		regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
				   MEM_CS_EN(spi->chip_select),
				   MEM_CS_MASK);
	}
	qspi->mmap_enabled = true;
}

static void ti_qspi_disable_memory_map(struct spi_device *spi)
{
	struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);

	ti_qspi_write(qspi, 0, QSPI_SPI_SWITCH_REG);
	if (qspi->ctrl_base)
		regmap_update_bits(qspi->ctrl_base, qspi->ctrl_reg,
				   0, MEM_CS_MASK);
	qspi->mmap_enabled = false;
}

static void ti_qspi_setup_mmap_read(struct spi_device *spi,
				    struct spi_flash_read_message *msg)
{
	struct ti_qspi  *qspi = spi_master_get_devdata(spi->master);
	u32 memval = msg->read_opcode;

	switch (msg->data_nbits) {
	case SPI_NBITS_QUAD:
		memval |= QSPI_SETUP_RD_QUAD;
		break;
	case SPI_NBITS_DUAL:
		memval |= QSPI_SETUP_RD_DUAL;
		break;
	default:
		memval |= QSPI_SETUP_RD_NORMAL;
		break;
	}
	memval |= ((msg->addr_width - 1) << QSPI_SETUP_ADDR_SHIFT |
		   msg->dummy_bytes << QSPI_SETUP_DUMMY_SHIFT);
	ti_qspi_write(qspi, memval,
		      QSPI_SPI_SETUP_REG(spi->chip_select));
}

static int ti_qspi_spi_flash_read(struct  spi_device *spi,
				  struct spi_flash_read_message *msg)
{
	struct ti_qspi *qspi = spi_master_get_devdata(spi->master);
	int ret = 0;

	mutex_lock(&qspi->list_lock);

	if (!qspi->mmap_enabled)
		ti_qspi_enable_memory_map(spi);
	ti_qspi_setup_mmap_read(spi, msg);
	memcpy_fromio(msg->buf, qspi->mmap_base + msg->from, msg->len);
	msg->retlen = msg->len;

	mutex_unlock(&qspi->list_lock);

	return ret;
}

static int ti_qspi_start_transfer_one(struct spi_master *master,
		struct spi_message *m)
{
@@ -398,6 +475,9 @@ static int ti_qspi_start_transfer_one(struct spi_master *master,

	mutex_lock(&qspi->list_lock);

	if (qspi->mmap_enabled)
		ti_qspi_disable_memory_map(spi);

	list_for_each_entry(t, &m->transfers, transfer_list) {
		qspi->cmd |= QSPI_WLEN(t->bits_per_word);

@@ -441,7 +521,7 @@ static int ti_qspi_probe(struct platform_device *pdev)
{
	struct  ti_qspi *qspi;
	struct spi_master *master;
	struct resource         *r, *res_ctrl, *res_mmap;
	struct resource         *r, *res_mmap;
	struct device_node *np = pdev->dev.of_node;
	u32 max_freq;
	int ret = 0, num_cs, irq;
@@ -487,16 +567,6 @@ static int ti_qspi_probe(struct platform_device *pdev)
		}
	}

	res_ctrl = platform_get_resource_byname(pdev,
			IORESOURCE_MEM, "qspi_ctrlmod");
	if (res_ctrl == NULL) {
		res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2);
		if (res_ctrl == NULL) {
			dev_dbg(&pdev->dev,
				"control module resources not required\n");
		}
	}

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(&pdev->dev, "no irq resource?\n");
@@ -511,20 +581,31 @@ static int ti_qspi_probe(struct platform_device *pdev)
		goto free_master;
	}

	if (res_ctrl) {
		qspi->ctrl_mod = true;
		qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl);
		if (IS_ERR(qspi->ctrl_base)) {
			ret = PTR_ERR(qspi->ctrl_base);
			goto free_master;
	if (res_mmap) {
		qspi->mmap_base = devm_ioremap_resource(&pdev->dev,
							res_mmap);
		master->spi_flash_read = ti_qspi_spi_flash_read;
		if (IS_ERR(qspi->mmap_base)) {
			dev_err(&pdev->dev,
				"falling back to PIO mode\n");
			master->spi_flash_read = NULL;
		}
	}
	qspi->mmap_enabled = false;

	if (res_mmap) {
		qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap);
		if (IS_ERR(qspi->mmap_base)) {
			ret = PTR_ERR(qspi->mmap_base);
			goto free_master;
	if (of_property_read_bool(np, "syscon-chipselects")) {
		qspi->ctrl_base =
		syscon_regmap_lookup_by_phandle(np,
						"syscon-chipselects");
		if (IS_ERR(qspi->ctrl_base))
			return PTR_ERR(qspi->ctrl_base);
		ret = of_property_read_u32_index(np,
						 "syscon-chipselects",
						 1, &qspi->ctrl_reg);
		if (ret) {
			dev_err(&pdev->dev,
				"couldn't get ctrl_mod reg index\n");
			return ret;
		}
	}

Loading