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

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

Merge remote-tracking branch 'spi/topic/rspi' into spi-next

parents b3d6c800 cb52c673
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -370,7 +370,7 @@ config SPI_PXA2XX_PCI

config SPI_RSPI
	tristate "Renesas RSPI controller"
	depends on SUPERH && SH_DMAE_BASE
	depends on (SUPERH || ARCH_SHMOBILE) && SH_DMAE_BASE
	help
	  SPI driver for Renesas RSPI blocks.

+231 −39
Original line number Diff line number Diff line
@@ -59,6 +59,14 @@
#define RSPI_SPCMD6		0x1c
#define RSPI_SPCMD7		0x1e

/*qspi only */
#define QSPI_SPBFCR		0x18
#define QSPI_SPBDCR		0x1a
#define QSPI_SPBMUL0		0x1c
#define QSPI_SPBMUL1		0x20
#define QSPI_SPBMUL2		0x24
#define QSPI_SPBMUL3		0x28

/* SPCR */
#define SPCR_SPRIE		0x80
#define SPCR_SPE		0x40
@@ -126,6 +134,8 @@
#define SPCMD_LSBF		0x1000
#define SPCMD_SPB_MASK		0x0f00
#define SPCMD_SPB_8_TO_16(bit)	(((bit - 1) << 8) & SPCMD_SPB_MASK)
#define SPCMD_SPB_8BIT		0x0000	/* qspi only */
#define SPCMD_SPB_16BIT		0x0100
#define SPCMD_SPB_20BIT		0x0000
#define SPCMD_SPB_24BIT		0x0100
#define SPCMD_SPB_32BIT		0x0200
@@ -135,6 +145,10 @@
#define SPCMD_CPOL		0x0002
#define SPCMD_CPHA		0x0001

/* SPBFCR */
#define SPBFCR_TXRST		0x80	/* qspi only */
#define SPBFCR_RXRST		0x40	/* qspi only */

struct rspi_data {
	void __iomem *addr;
	u32 max_speed_hz;
@@ -145,6 +159,7 @@ struct rspi_data {
	spinlock_t lock;
	struct clk *clk;
	unsigned char spsr;
	const struct spi_ops *ops;

	/* for dmaengine */
	struct dma_chan *chan_tx;
@@ -165,6 +180,11 @@ static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset)
	iowrite16(data, rspi->addr + offset);
}

static void rspi_write32(struct rspi_data *rspi, u32 data, u16 offset)
{
	iowrite32(data, rspi->addr + offset);
}

static u8 rspi_read8(struct rspi_data *rspi, u16 offset)
{
	return ioread8(rspi->addr + offset);
@@ -175,17 +195,103 @@ static u16 rspi_read16(struct rspi_data *rspi, u16 offset)
	return ioread16(rspi->addr + offset);
}

static unsigned char rspi_calc_spbr(struct rspi_data *rspi)
/* optional functions */
struct spi_ops {
	int (*set_config_register)(struct rspi_data *rspi, int access_size);
	int (*send_pio)(struct rspi_data *rspi, struct spi_message *mesg,
			struct spi_transfer *t);
	int (*receive_pio)(struct rspi_data *rspi, struct spi_message *mesg,
			   struct spi_transfer *t);

};

/*
 * functions for RSPI
 */
static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
{
	int spbr;

	/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
	rspi_write8(rspi, 0x00, RSPI_SPPCR);

	/* Sets transfer bit rate */
	spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
	rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);

	/* Sets number of frames to be used: 1 frame */
	rspi_write8(rspi, 0x00, RSPI_SPDCR);

	/* Sets RSPCK, SSL, next-access delay value */
	rspi_write8(rspi, 0x00, RSPI_SPCKD);
	rspi_write8(rspi, 0x00, RSPI_SSLND);
	rspi_write8(rspi, 0x00, RSPI_SPND);

	/* Sets parity, interrupt mask */
	rspi_write8(rspi, 0x00, RSPI_SPCR2);

	/* Sets SPCMD */
	rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP,
		     RSPI_SPCMD0);

	/* Sets RSPI mode */
	rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);

	return 0;
}

/*
 * functions for QSPI
 */
static int qspi_set_config_register(struct rspi_data *rspi, int access_size)
{
	int tmp;
	unsigned char spbr;
	u16 spcmd;
	int spbr;

	/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
	rspi_write8(rspi, 0x00, RSPI_SPPCR);

	/* Sets transfer bit rate */
	spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz);
	rspi_write8(rspi, clamp(spbr, 0, 255), RSPI_SPBR);

	/* Sets number of frames to be used: 1 frame */
	rspi_write8(rspi, 0x00, RSPI_SPDCR);

	/* Sets RSPCK, SSL, next-access delay value */
	rspi_write8(rspi, 0x00, RSPI_SPCKD);
	rspi_write8(rspi, 0x00, RSPI_SSLND);
	rspi_write8(rspi, 0x00, RSPI_SPND);

	/* Data Length Setting */
	if (access_size == 8)
		spcmd = SPCMD_SPB_8BIT;
	else if (access_size == 16)
		spcmd = SPCMD_SPB_16BIT;
	else if (access_size == 32)
		spcmd = SPCMD_SPB_32BIT;

	spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SSLKP | SPCMD_SPNDEN;

	/* Resets transfer data length */
	rspi_write32(rspi, 0, QSPI_SPBMUL0);

	/* Resets transmit and receive buffer */
	rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
	/* Sets buffer to allow normal operation */
	rspi_write8(rspi, 0x00, QSPI_SPBFCR);

	/* Sets SPCMD */
	rspi_write16(rspi, spcmd, RSPI_SPCMD0);

	tmp = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1;
	spbr = clamp(tmp, 0, 255);
	/* Enables SPI function in a master mode */
	rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR);

	return spbr;
	return 0;
}

#define set_config_register(spi, n) spi->ops->set_config_register(spi, n)

static void rspi_enable_irq(struct rspi_data *rspi, u8 enable)
{
	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR);
@@ -220,54 +326,60 @@ static void rspi_negate_ssl(struct rspi_data *rspi)
	rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR);
}

static int rspi_set_config_register(struct rspi_data *rspi, int access_size)
static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
			 struct spi_transfer *t)
{
	/* Sets output mode(CMOS) and MOSI signal(from previous transfer) */
	rspi_write8(rspi, 0x00, RSPI_SPPCR);

	/* Sets transfer bit rate */
	rspi_write8(rspi, rspi_calc_spbr(rspi), RSPI_SPBR);

	/* Sets number of frames to be used: 1 frame */
	rspi_write8(rspi, 0x00, RSPI_SPDCR);
	int remain = t->len;
	u8 *data;

	/* Sets RSPCK, SSL, next-access delay value */
	rspi_write8(rspi, 0x00, RSPI_SPCKD);
	rspi_write8(rspi, 0x00, RSPI_SSLND);
	rspi_write8(rspi, 0x00, RSPI_SPND);
	data = (u8 *)t->tx_buf;
	while (remain > 0) {
		rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
			    RSPI_SPCR);

	/* Sets parity, interrupt mask */
	rspi_write8(rspi, 0x00, RSPI_SPCR2);
		if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
			dev_err(&rspi->master->dev,
				"%s: tx empty timeout\n", __func__);
			return -ETIMEDOUT;
		}

	/* Sets SPCMD */
	rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP,
		     RSPI_SPCMD0);
		rspi_write16(rspi, *data, RSPI_SPDR);
		data++;
		remain--;
	}

	/* Sets RSPI mode */
	rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR);
	/* Waiting for the last transmition */
	rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);

	return 0;
}

static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
			 struct spi_transfer *t)
{
	int remain = t->len;
	u8 *data;

	rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
	rspi_write8(rspi, 0x00, QSPI_SPBFCR);

	data = (u8 *)t->tx_buf;
	while (remain > 0) {
		rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
			    RSPI_SPCR);

		if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
			dev_err(&rspi->master->dev,
				"%s: tx empty timeout\n", __func__);
			return -ETIMEDOUT;
		}
		rspi_write8(rspi, *data++, RSPI_SPDR);

		if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
			dev_err(&rspi->master->dev,
				"%s: receive timeout\n", __func__);
			return -ETIMEDOUT;
		}
		rspi_read8(rspi, RSPI_SPDR);

		rspi_write16(rspi, *data, RSPI_SPDR);
		data++;
		remain--;
	}

@@ -277,6 +389,8 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
	return 0;
}

#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)

static void rspi_dma_complete(void *arg)
{
	struct rspi_data *rspi = arg;
@@ -442,6 +556,51 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
	return 0;
}

static void qspi_receive_init(struct rspi_data *rspi)
{
	unsigned char spsr;

	spsr = rspi_read8(rspi, RSPI_SPSR);
	if (spsr & SPSR_SPRF)
		rspi_read8(rspi, RSPI_SPDR);   /* dummy read */
	rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR);
	rspi_write8(rspi, 0x00, QSPI_SPBFCR);
}

static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
			    struct spi_transfer *t)
{
	int remain = t->len;
	u8 *data;

	qspi_receive_init(rspi);

	data = (u8 *)t->rx_buf;
	while (remain > 0) {

		if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
			dev_err(&rspi->master->dev,
				"%s: tx empty timeout\n", __func__);
			return -ETIMEDOUT;
		}
		/* dummy write for generate clock */
		rspi_write8(rspi, 0x00, RSPI_SPDR);

		if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) {
			dev_err(&rspi->master->dev,
				"%s: receive timeout\n", __func__);
			return -ETIMEDOUT;
		}
		/* SPDR allows 8, 16 or 32-bit access */
		*data++ = rspi_read8(rspi, RSPI_SPDR);
		remain--;
	}

	return 0;
}

#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t)

static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
{
	struct scatterlist sg, sg_dummy;
@@ -581,7 +740,7 @@ static void rspi_work(struct work_struct *work)
				if (rspi_is_dma(rspi, t))
					ret = rspi_send_dma(rspi, t);
				else
					ret = rspi_send_pio(rspi, mesg, t);
					ret = send_pio(rspi, mesg, t);
				if (ret < 0)
					goto error;
			}
@@ -589,7 +748,7 @@ static void rspi_work(struct work_struct *work)
				if (rspi_is_dma(rspi, t))
					ret = rspi_receive_dma(rspi, t);
				else
					ret = rspi_receive_pio(rspi, mesg, t);
					ret = receive_pio(rspi, mesg, t);
				if (ret < 0)
					goto error;
			}
@@ -616,7 +775,7 @@ static int rspi_setup(struct spi_device *spi)
		spi->bits_per_word = 8;
	rspi->max_speed_hz = spi->max_speed_hz;

	rspi_set_config_register(rspi, 8);
	set_config_register(rspi, 8);

	return 0;
}
@@ -745,7 +904,16 @@ static int rspi_probe(struct platform_device *pdev)
	struct rspi_data *rspi;
	int ret, irq;
	char clk_name[16];

	struct rspi_plat_data *rspi_pd = pdev->dev.platform_data;
	const struct spi_ops *ops;
	const struct platform_device_id *id_entry = pdev->id_entry;

	ops = (struct spi_ops *)id_entry->driver_data;
	/* ops parameter check */
	if (!ops->set_config_register) {
		dev_err(&pdev->dev, "there is no set_config_register\n");
		return -ENODEV;
	}
	/* get base addr */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (unlikely(res == NULL)) {
@@ -767,7 +935,7 @@ static int rspi_probe(struct platform_device *pdev)

	rspi = spi_master_get_devdata(master);
	platform_set_drvdata(pdev, rspi);

	rspi->ops = ops;
	rspi->master = master;
	rspi->addr = ioremap(res->start, resource_size(res));
	if (rspi->addr == NULL) {
@@ -776,7 +944,7 @@ static int rspi_probe(struct platform_device *pdev)
		goto error1;
	}

	snprintf(clk_name, sizeof(clk_name), "rspi%d", pdev->id);
	snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id);
	rspi->clk = clk_get(&pdev->dev, clk_name);
	if (IS_ERR(rspi->clk)) {
		dev_err(&pdev->dev, "cannot get clock\n");
@@ -790,7 +958,10 @@ static int rspi_probe(struct platform_device *pdev)
	INIT_WORK(&rspi->ws, rspi_work);
	init_waitqueue_head(&rspi->wait);

	master->num_chipselect = 2;
	master->num_chipselect = rspi_pd->num_chipselect;
	if (!master->num_chipselect)
		master->num_chipselect = 2; /* default */

	master->bus_num = pdev->id;
	master->setup = rspi_setup;
	master->transfer = rspi_transfer;
@@ -832,11 +1003,32 @@ error1:
	return ret;
}

static struct spi_ops rspi_ops = {
	.set_config_register =		rspi_set_config_register,
	.send_pio =			rspi_send_pio,
	.receive_pio =			rspi_receive_pio,
};

static struct spi_ops qspi_ops = {
	.set_config_register =		qspi_set_config_register,
	.send_pio =			qspi_send_pio,
	.receive_pio =			qspi_receive_pio,
};

static struct platform_device_id spi_driver_ids[] = {
	{ "rspi",	(kernel_ulong_t)&rspi_ops },
	{ "qspi",	(kernel_ulong_t)&qspi_ops },
	{},
};

MODULE_DEVICE_TABLE(platform, spi_driver_ids);

static struct platform_driver rspi_driver = {
	.probe =	rspi_probe,
	.remove =	rspi_remove,
	.id_table =	spi_driver_ids,
	.driver		= {
		.name = "rspi",
		.name = "renesas_spi",
		.owner	= THIS_MODULE,
	},
};
+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ struct rspi_plat_data {
	unsigned int dma_rx_id;

	unsigned dma_width_16bit:1;	/* DMAC read/write width = 16-bit */

	u16 num_chipselect;
};

#endif