Commit ad14ad73 authored by Mark Brown's avatar Mark Brown

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

parents b3d6c800 cb52c673
...@@ -370,7 +370,7 @@ config SPI_PXA2XX_PCI ...@@ -370,7 +370,7 @@ config SPI_PXA2XX_PCI
config SPI_RSPI config SPI_RSPI
tristate "Renesas RSPI controller" tristate "Renesas RSPI controller"
depends on SUPERH && SH_DMAE_BASE depends on (SUPERH || ARCH_SHMOBILE) && SH_DMAE_BASE
help help
SPI driver for Renesas RSPI blocks. SPI driver for Renesas RSPI blocks.
......
...@@ -59,6 +59,14 @@ ...@@ -59,6 +59,14 @@
#define RSPI_SPCMD6 0x1c #define RSPI_SPCMD6 0x1c
#define RSPI_SPCMD7 0x1e #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 */ /* SPCR */
#define SPCR_SPRIE 0x80 #define SPCR_SPRIE 0x80
#define SPCR_SPE 0x40 #define SPCR_SPE 0x40
...@@ -126,6 +134,8 @@ ...@@ -126,6 +134,8 @@
#define SPCMD_LSBF 0x1000 #define SPCMD_LSBF 0x1000
#define SPCMD_SPB_MASK 0x0f00 #define SPCMD_SPB_MASK 0x0f00
#define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK) #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_20BIT 0x0000
#define SPCMD_SPB_24BIT 0x0100 #define SPCMD_SPB_24BIT 0x0100
#define SPCMD_SPB_32BIT 0x0200 #define SPCMD_SPB_32BIT 0x0200
...@@ -135,6 +145,10 @@ ...@@ -135,6 +145,10 @@
#define SPCMD_CPOL 0x0002 #define SPCMD_CPOL 0x0002
#define SPCMD_CPHA 0x0001 #define SPCMD_CPHA 0x0001
/* SPBFCR */
#define SPBFCR_TXRST 0x80 /* qspi only */
#define SPBFCR_RXRST 0x40 /* qspi only */
struct rspi_data { struct rspi_data {
void __iomem *addr; void __iomem *addr;
u32 max_speed_hz; u32 max_speed_hz;
...@@ -145,6 +159,7 @@ struct rspi_data { ...@@ -145,6 +159,7 @@ struct rspi_data {
spinlock_t lock; spinlock_t lock;
struct clk *clk; struct clk *clk;
unsigned char spsr; unsigned char spsr;
const struct spi_ops *ops;
/* for dmaengine */ /* for dmaengine */
struct dma_chan *chan_tx; struct dma_chan *chan_tx;
...@@ -165,6 +180,11 @@ static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset) ...@@ -165,6 +180,11 @@ static void rspi_write16(struct rspi_data *rspi, u16 data, u16 offset)
iowrite16(data, rspi->addr + 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) static u8 rspi_read8(struct rspi_data *rspi, u16 offset)
{ {
return ioread8(rspi->addr + offset); return ioread8(rspi->addr + offset);
...@@ -175,17 +195,103 @@ static u16 rspi_read16(struct rspi_data *rspi, u16 offset) ...@@ -175,17 +195,103 @@ static u16 rspi_read16(struct rspi_data *rspi, u16 offset)
return ioread16(rspi->addr + 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; u16 spcmd;
unsigned char spbr; 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; /* Enables SPI function in a master mode */
spbr = clamp(tmp, 0, 255); 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) static void rspi_enable_irq(struct rspi_data *rspi, u8 enable)
{ {
rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR); rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | enable, RSPI_SPCR);
...@@ -220,54 +326,60 @@ static void rspi_negate_ssl(struct rspi_data *rspi) ...@@ -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); 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) */ int remain = t->len;
rspi_write8(rspi, 0x00, RSPI_SPPCR); u8 *data;
/* 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);
/* Sets RSPCK, SSL, next-access delay value */ data = (u8 *)t->tx_buf;
rspi_write8(rspi, 0x00, RSPI_SPCKD); while (remain > 0) {
rspi_write8(rspi, 0x00, RSPI_SSLND); rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD,
rspi_write8(rspi, 0x00, RSPI_SPND); RSPI_SPCR);
/* Sets parity, interrupt mask */ if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
rspi_write8(rspi, 0x00, RSPI_SPCR2); dev_err(&rspi->master->dev,
"%s: tx empty timeout\n", __func__);
return -ETIMEDOUT;
}
/* Sets SPCMD */ rspi_write16(rspi, *data, RSPI_SPDR);
rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | SPCMD_SSLKP, data++;
RSPI_SPCMD0); remain--;
}
/* Sets RSPI mode */ /* Waiting for the last transmition */
rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE);
return 0; 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) struct spi_transfer *t)
{ {
int remain = t->len; int remain = t->len;
u8 *data; u8 *data;
rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR);
rspi_write8(rspi, 0x00, QSPI_SPBFCR);
data = (u8 *)t->tx_buf; data = (u8 *)t->tx_buf;
while (remain > 0) { 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) { if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) {
dev_err(&rspi->master->dev, dev_err(&rspi->master->dev,
"%s: tx empty timeout\n", __func__); "%s: tx empty timeout\n", __func__);
return -ETIMEDOUT; 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--; remain--;
} }
...@@ -277,6 +389,8 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, ...@@ -277,6 +389,8 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg,
return 0; return 0;
} }
#define send_pio(spi, mesg, t) spi->ops->send_pio(spi, mesg, t)
static void rspi_dma_complete(void *arg) static void rspi_dma_complete(void *arg)
{ {
struct rspi_data *rspi = arg; struct rspi_data *rspi = arg;
...@@ -442,6 +556,51 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, ...@@ -442,6 +556,51 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg,
return 0; 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) static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t)
{ {
struct scatterlist sg, sg_dummy; struct scatterlist sg, sg_dummy;
...@@ -581,7 +740,7 @@ static void rspi_work(struct work_struct *work) ...@@ -581,7 +740,7 @@ static void rspi_work(struct work_struct *work)
if (rspi_is_dma(rspi, t)) if (rspi_is_dma(rspi, t))
ret = rspi_send_dma(rspi, t); ret = rspi_send_dma(rspi, t);
else else
ret = rspi_send_pio(rspi, mesg, t); ret = send_pio(rspi, mesg, t);
if (ret < 0) if (ret < 0)
goto error; goto error;
} }
...@@ -589,7 +748,7 @@ static void rspi_work(struct work_struct *work) ...@@ -589,7 +748,7 @@ static void rspi_work(struct work_struct *work)
if (rspi_is_dma(rspi, t)) if (rspi_is_dma(rspi, t))
ret = rspi_receive_dma(rspi, t); ret = rspi_receive_dma(rspi, t);
else else
ret = rspi_receive_pio(rspi, mesg, t); ret = receive_pio(rspi, mesg, t);
if (ret < 0) if (ret < 0)
goto error; goto error;
} }
...@@ -616,7 +775,7 @@ static int rspi_setup(struct spi_device *spi) ...@@ -616,7 +775,7 @@ static int rspi_setup(struct spi_device *spi)
spi->bits_per_word = 8; spi->bits_per_word = 8;
rspi->max_speed_hz = spi->max_speed_hz; rspi->max_speed_hz = spi->max_speed_hz;
rspi_set_config_register(rspi, 8); set_config_register(rspi, 8);
return 0; return 0;
} }
...@@ -745,7 +904,16 @@ static int rspi_probe(struct platform_device *pdev) ...@@ -745,7 +904,16 @@ static int rspi_probe(struct platform_device *pdev)
struct rspi_data *rspi; struct rspi_data *rspi;
int ret, irq; int ret, irq;
char clk_name[16]; 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 */ /* get base addr */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (unlikely(res == NULL)) { if (unlikely(res == NULL)) {
...@@ -767,7 +935,7 @@ static int rspi_probe(struct platform_device *pdev) ...@@ -767,7 +935,7 @@ static int rspi_probe(struct platform_device *pdev)
rspi = spi_master_get_devdata(master); rspi = spi_master_get_devdata(master);
platform_set_drvdata(pdev, rspi); platform_set_drvdata(pdev, rspi);
rspi->ops = ops;
rspi->master = master; rspi->master = master;
rspi->addr = ioremap(res->start, resource_size(res)); rspi->addr = ioremap(res->start, resource_size(res));
if (rspi->addr == NULL) { if (rspi->addr == NULL) {
...@@ -776,7 +944,7 @@ static int rspi_probe(struct platform_device *pdev) ...@@ -776,7 +944,7 @@ static int rspi_probe(struct platform_device *pdev)
goto error1; 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); rspi->clk = clk_get(&pdev->dev, clk_name);
if (IS_ERR(rspi->clk)) { if (IS_ERR(rspi->clk)) {
dev_err(&pdev->dev, "cannot get clock\n"); dev_err(&pdev->dev, "cannot get clock\n");
...@@ -790,7 +958,10 @@ static int rspi_probe(struct platform_device *pdev) ...@@ -790,7 +958,10 @@ static int rspi_probe(struct platform_device *pdev)
INIT_WORK(&rspi->ws, rspi_work); INIT_WORK(&rspi->ws, rspi_work);
init_waitqueue_head(&rspi->wait); 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->bus_num = pdev->id;
master->setup = rspi_setup; master->setup = rspi_setup;
master->transfer = rspi_transfer; master->transfer = rspi_transfer;
...@@ -832,11 +1003,32 @@ static int rspi_probe(struct platform_device *pdev) ...@@ -832,11 +1003,32 @@ static int rspi_probe(struct platform_device *pdev)
return ret; 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 = { static struct platform_driver rspi_driver = {
.probe = rspi_probe, .probe = rspi_probe,
.remove = rspi_remove, .remove = rspi_remove,
.id_table = spi_driver_ids,
.driver = { .driver = {
.name = "rspi", .name = "renesas_spi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
}; };
......
...@@ -26,6 +26,8 @@ struct rspi_plat_data { ...@@ -26,6 +26,8 @@ struct rspi_plat_data {
unsigned int dma_rx_id; unsigned int dma_rx_id;
unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */ unsigned dma_width_16bit:1; /* DMAC read/write width = 16-bit */
u16 num_chipselect;
}; };
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment