From 91949a2d4a96195ccd37322fafe8d16c68dda86e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:51 +0100 Subject: [PATCH 001/201] spi: rspi: Remove unused mesg parameter from {send,receive}_pio() Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 28987d9fcfe5..ccd5cf201d04 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -228,11 +228,8 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset) struct spi_ops { int (*set_config_register)(const 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); - + int (*send_pio)(struct rspi_data *rspi, struct spi_transfer *t); + int (*receive_pio)(struct rspi_data *rspi, struct spi_transfer *t); }; /* @@ -358,8 +355,7 @@ static void rspi_negate_ssl(const struct rspi_data *rspi) rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); } -static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) { int remain = t->len; const u8 *data = t->tx_buf; @@ -384,8 +380,7 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, return 0; } -static int qspi_send_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) { int remain = t->len; const u8 *data = t->tx_buf; @@ -418,7 +413,7 @@ static int qspi_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) +#define send_pio(spi, t) spi->ops->send_pio(spi, t) static void rspi_dma_complete(void *arg) { @@ -551,8 +546,7 @@ static void rspi_receive_init(const struct rspi_data *rspi) RSPI_SPSR); } -static int rspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) { int remain = t->len; u8 *data; @@ -598,8 +592,7 @@ static void qspi_receive_init(const struct rspi_data *rspi) rspi_write8(rspi, 0x00, QSPI_SPBFCR); } -static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, - struct spi_transfer *t) +static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) { int remain = t->len; u8 *data; @@ -630,7 +623,7 @@ static int qspi_receive_pio(struct rspi_data *rspi, struct spi_message *mesg, return 0; } -#define receive_pio(spi, mesg, t) spi->ops->receive_pio(spi, mesg, t) +#define receive_pio(spi, t) spi->ops->receive_pio(spi, t) static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) { @@ -771,7 +764,7 @@ static void rspi_work(struct work_struct *work) if (rspi_is_dma(rspi, t)) ret = rspi_send_dma(rspi, t); else - ret = send_pio(rspi, mesg, t); + ret = send_pio(rspi, t); if (ret < 0) goto error; } @@ -779,7 +772,7 @@ static void rspi_work(struct work_struct *work) if (rspi_is_dma(rspi, t)) ret = rspi_receive_dma(rspi, t); else - ret = receive_pio(rspi, mesg, t); + ret = receive_pio(rspi, t); if (ret < 0) goto error; } From 79d2349542f38663c3096f389115b1f131d6e564 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:52 +0100 Subject: [PATCH 002/201] spi: rspi: Use core message handling Let the generic SPI core handle SPI messages, calling into our rspi_transfer_one() method. rspi_assert_ssl() and rspi_negate_ssl() are absorbed into rspi_prepare_message() and rspi_unprepare_message(), as they actually enable/disable the whole SPI function, instead of just (de)asserting the chip select line. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 111 +++++++++++++---------------------------- 1 file changed, 34 insertions(+), 77 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index ccd5cf201d04..0e4d169c90d7 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -25,8 +25,6 @@ #include #include #include -#include -#include #include #include #include @@ -181,10 +179,7 @@ struct rspi_data { void __iomem *addr; u32 max_speed_hz; struct spi_master *master; - struct list_head queue; - struct work_struct ws; wait_queue_head_t wait; - spinlock_t lock; struct clk *clk; u8 spsr; u16 spcmd; @@ -345,16 +340,6 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, return 0; } -static void rspi_assert_ssl(const struct rspi_data *rspi) -{ - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); -} - -static void rspi_negate_ssl(const struct rspi_data *rspi) -{ - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); -} - static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) { int remain = t->len; @@ -739,56 +724,27 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t) return 0; } -static void rspi_work(struct work_struct *work) +static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) { - struct rspi_data *rspi = container_of(work, struct rspi_data, ws); - struct spi_message *mesg; - struct spi_transfer *t; - unsigned long flags; - int ret; + struct rspi_data *rspi = spi_master_get_devdata(master); + int ret = 0; - while (1) { - spin_lock_irqsave(&rspi->lock, flags); - if (list_empty(&rspi->queue)) { - spin_unlock_irqrestore(&rspi->lock, flags); - break; - } - mesg = list_entry(rspi->queue.next, struct spi_message, queue); - list_del_init(&mesg->queue); - spin_unlock_irqrestore(&rspi->lock, flags); - - rspi_assert_ssl(rspi); - - list_for_each_entry(t, &mesg->transfers, transfer_list) { - if (t->tx_buf) { - if (rspi_is_dma(rspi, t)) - ret = rspi_send_dma(rspi, t); - else - ret = send_pio(rspi, t); - if (ret < 0) - goto error; - } - if (t->rx_buf) { - if (rspi_is_dma(rspi, t)) - ret = rspi_receive_dma(rspi, t); - else - ret = receive_pio(rspi, t); - if (ret < 0) - goto error; - } - mesg->actual_length += t->len; - } - rspi_negate_ssl(rspi); - - mesg->status = 0; - mesg->complete(mesg->context); + if (xfer->tx_buf) { + if (rspi_is_dma(rspi, xfer)) + ret = rspi_send_dma(rspi, xfer); + else + ret = send_pio(rspi, xfer); + if (ret < 0) + return ret; } - - return; - -error: - mesg->status = ret; - mesg->complete(mesg->context); + if (xfer->rx_buf) { + if (rspi_is_dma(rspi, xfer)) + ret = rspi_receive_dma(rspi, xfer); + else + ret = receive_pio(rspi, xfer); + } + return ret; } static int rspi_setup(struct spi_device *spi) @@ -808,24 +764,26 @@ static int rspi_setup(struct spi_device *spi) return 0; } -static int rspi_transfer(struct spi_device *spi, struct spi_message *mesg) +static void rspi_cleanup(struct spi_device *spi) { - struct rspi_data *rspi = spi_master_get_devdata(spi->master); - unsigned long flags; +} - mesg->actual_length = 0; - mesg->status = -EINPROGRESS; - - spin_lock_irqsave(&rspi->lock, flags); - list_add_tail(&mesg->queue, &rspi->queue); - schedule_work(&rspi->ws); - spin_unlock_irqrestore(&rspi->lock, flags); +static int rspi_prepare_message(struct spi_master *master, + struct spi_message *message) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); return 0; } -static void rspi_cleanup(struct spi_device *spi) +static int rspi_unprepare_message(struct spi_master *master, + struct spi_message *message) { + struct rspi_data *rspi = spi_master_get_devdata(master); + + rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); + return 0; } static irqreturn_t rspi_irq(int irq, void *_sr) @@ -972,9 +930,6 @@ static int rspi_probe(struct platform_device *pdev) } clk_enable(rspi->clk); - INIT_LIST_HEAD(&rspi->queue); - spin_lock_init(&rspi->lock); - INIT_WORK(&rspi->ws, rspi_work); init_waitqueue_head(&rspi->wait); if (rspi_pd && rspi_pd->num_chipselect) @@ -984,8 +939,10 @@ static int rspi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->setup = rspi_setup; - master->transfer = rspi_transfer; + master->transfer_one = rspi_transfer_one; master->cleanup = rspi_cleanup; + master->prepare_message = rspi_prepare_message; + master->unprepare_message = rspi_unprepare_message; master->mode_bits = SPI_CPHA | SPI_CPOL; ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0, From 74da76865d57161cadf8f324281f23ed3eb5db9c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:53 +0100 Subject: [PATCH 003/201] spi: rspi: Abstract 8/16-bit Data Register access Add rspi_{write,read}_data(), to abstract 8-bit (QSPI, and RSPI on RZ/A1H) versus 16-bit (RSPI) Data Register access. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 56 ++++++++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 0e4d169c90d7..a0bb3c28ae91 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -192,6 +192,7 @@ struct rspi_data { unsigned dma_width_16bit:1; unsigned dma_callbacked:1; + unsigned byte_access:1; }; static void rspi_write8(const struct rspi_data *rspi, u8 data, u16 offset) @@ -219,10 +220,25 @@ static u16 rspi_read16(const struct rspi_data *rspi, u16 offset) return ioread16(rspi->addr + offset); } +static void rspi_write_data(const struct rspi_data *rspi, u16 data) +{ + if (rspi->byte_access) + rspi_write8(rspi, data, RSPI_SPDR); + else /* 16 bit */ + rspi_write16(rspi, data, RSPI_SPDR); +} + +static u16 rspi_read_data(const struct rspi_data *rspi) +{ + if (rspi->byte_access) + return rspi_read8(rspi, RSPI_SPDR); + else /* 16 bit */ + return rspi_read16(rspi, RSPI_SPDR); +} + /* optional functions */ struct spi_ops { - int (*set_config_register)(const struct rspi_data *rspi, - int access_size); + int (*set_config_register)(struct rspi_data *rspi, int access_size); int (*send_pio)(struct rspi_data *rspi, struct spi_transfer *t); int (*receive_pio)(struct rspi_data *rspi, struct spi_transfer *t); }; @@ -230,8 +246,7 @@ struct spi_ops { /* * functions for RSPI */ -static int rspi_set_config_register(const struct rspi_data *rspi, - int access_size) +static int rspi_set_config_register(struct rspi_data *rspi, int access_size) { int spbr; @@ -242,8 +257,9 @@ static int rspi_set_config_register(const struct rspi_data *rspi, 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); + /* Disable dummy transmission, set 16-bit word access, 1 frame */ + rspi_write8(rspi, 0, RSPI_SPDCR); + rspi->byte_access = 0; /* Sets RSPCK, SSL, next-access delay value */ rspi_write8(rspi, 0x00, RSPI_SPCKD); @@ -266,8 +282,7 @@ static int rspi_set_config_register(const struct rspi_data *rspi, /* * functions for QSPI */ -static int qspi_set_config_register(const struct rspi_data *rspi, - int access_size) +static int qspi_set_config_register(struct rspi_data *rspi, int access_size) { u16 spcmd; int spbr; @@ -279,8 +294,9 @@ static int qspi_set_config_register(const struct rspi_data *rspi, 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); + /* Disable dummy transmission, set byte access */ + rspi_write8(rspi, 0, RSPI_SPDCR); + rspi->byte_access = 1; /* Sets RSPCK, SSL, next-access delay value */ rspi_write8(rspi, 0x00, RSPI_SPCKD); @@ -354,7 +370,7 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) return -ETIMEDOUT; } - rspi_write16(rspi, *data, RSPI_SPDR); + rspi_write_data(rspi, *data); data++; remain--; } @@ -380,14 +396,14 @@ static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) "%s: tx empty timeout\n", __func__); return -ETIMEDOUT; } - rspi_write8(rspi, *data++, RSPI_SPDR); + rspi_write_data(rspi, *data++); 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_read_data(rspi); remain--; } @@ -525,7 +541,7 @@ static void rspi_receive_init(const struct rspi_data *rspi) spsr = rspi_read8(rspi, RSPI_SPSR); if (spsr & SPSR_SPRF) - rspi_read16(rspi, RSPI_SPDR); /* dummy read */ + rspi_read_data(rspi); /* dummy read */ if (spsr & SPSR_OVRF) rspi_write8(rspi, rspi_read8(rspi, RSPI_SPSR) & ~SPSR_OVRF, RSPI_SPSR); @@ -549,15 +565,14 @@ static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) return -ETIMEDOUT; } /* dummy write for generate clock */ - rspi_write16(rspi, DUMMY_DATA, RSPI_SPDR); + rspi_write_data(rspi, DUMMY_DATA); 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 16 or 32-bit access only */ - *data = (u8)rspi_read16(rspi, RSPI_SPDR); + *data = rspi_read_data(rspi); data++; remain--; @@ -572,7 +587,7 @@ static void qspi_receive_init(const struct rspi_data *rspi) spsr = rspi_read8(rspi, RSPI_SPSR); if (spsr & SPSR_SPRF) - rspi_read8(rspi, RSPI_SPDR); /* dummy read */ + rspi_read_data(rspi); /* dummy read */ rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, QSPI_SPBFCR); rspi_write8(rspi, 0x00, QSPI_SPBFCR); } @@ -593,15 +608,14 @@ static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) return -ETIMEDOUT; } /* dummy write for generate clock */ - rspi_write8(rspi, DUMMY_DATA, RSPI_SPDR); + rspi_write_data(rspi, DUMMY_DATA); 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); + *data++ = rspi_read_data(rspi); remain--; } From 35301c996046243ca6e41d490dea2823f045614c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:54 +0100 Subject: [PATCH 004/201] spi: rspi: Add rspi_data_{out,in,out_in}() helpers Add helpers rspi_data_{out,in,out_in}() to write, read, or write and read data to/from the Data Register, taking care of waiting until data or space is available in the buffers. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 117 ++++++++++++++++++++--------------------- 1 file changed, 56 insertions(+), 61 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index a0bb3c28ae91..4b27513e7204 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -356,22 +356,51 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, return 0; } +static int rspi_data_out(struct rspi_data *rspi, u8 data) +{ + if (rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE) < 0) { + dev_err(&rspi->master->dev, "transmit timeout\n"); + return -ETIMEDOUT; + } + rspi_write_data(rspi, data); + return 0; +} + +static int rspi_data_in(struct rspi_data *rspi) +{ + u8 data; + + if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { + dev_err(&rspi->master->dev, "receive timeout\n"); + return -ETIMEDOUT; + } + data = rspi_read_data(rspi); + return data; +} + +static int rspi_data_out_in(struct rspi_data *rspi, u8 data) +{ + int ret; + + ret = rspi_data_out(rspi, data); + if (ret < 0) + return ret; + + return rspi_data_in(rspi); +} + static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) { - int remain = t->len; + int remain = t->len, ret; const u8 *data = 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_write_data(rspi, *data); - data++; + ret = rspi_data_out(rspi, *data++); + if (ret < 0) + return ret; remain--; } @@ -383,28 +412,17 @@ static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) { - int remain = t->len; + int remain = t->len, ret; const u8 *data = t->tx_buf; rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR); rspi_write8(rspi, 0x00, QSPI_SPBFCR); 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; - } - rspi_write_data(rspi, *data++); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { - dev_err(&rspi->master->dev, - "%s: receive timeout\n", __func__); - return -ETIMEDOUT; - } - rspi_read_data(rspi); - + /* dummy read */ + ret = rspi_data_out_in(rspi, *data++); + if (ret < 0) + return ret; remain--; } @@ -549,32 +567,20 @@ static void rspi_receive_init(const struct rspi_data *rspi) static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) { - int remain = t->len; - u8 *data; + int remain = t->len, ret; + u8 *data = t->rx_buf; rspi_receive_init(rspi); - data = t->rx_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; - } - /* dummy write for generate clock */ - rspi_write_data(rspi, DUMMY_DATA); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { - dev_err(&rspi->master->dev, - "%s: receive timeout\n", __func__); - return -ETIMEDOUT; - } - *data = rspi_read_data(rspi); - - data++; + /* dummy write data for generate clock */ + ret = rspi_data_out_in(rspi, DUMMY_DATA); + if (ret < 0) + return ret; + *data++ = ret; remain--; } @@ -594,28 +600,17 @@ static void qspi_receive_init(const struct rspi_data *rspi) static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) { - int remain = t->len; - u8 *data; + int remain = t->len, ret; + u8 *data = t->rx_buf; qspi_receive_init(rspi); - data = 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_write_data(rspi, DUMMY_DATA); - - if (rspi_wait_for_interrupt(rspi, SPSR_SPRF, SPCR_SPRIE) < 0) { - dev_err(&rspi->master->dev, - "%s: receive timeout\n", __func__); - return -ETIMEDOUT; - } - *data++ = rspi_read_data(rspi); + ret = rspi_data_out_in(rspi, DUMMY_DATA); + if (ret < 0) + return ret; + *data++ = ret; remain--; } From eb557f75269e82dd26a79be536eca223ddc3eaf7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:55 +0100 Subject: [PATCH 005/201] spi: rspi: Abstract transfer_one() for RSPI and QSPI Split off qspi_transfer_one() (which doesn't support DMA yet) from rspi_transfer_one(). Replace the abstraction of send_pio()/receive_pio() by the abstracrion of transfer_one(). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 4b27513e7204..d837c5029308 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -239,8 +239,8 @@ static u16 rspi_read_data(const 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_transfer *t); - int (*receive_pio)(struct rspi_data *rspi, struct spi_transfer *t); + int (*transfer_one)(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer); }; /* @@ -432,8 +432,6 @@ static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) return 0; } -#define send_pio(spi, t) spi->ops->send_pio(spi, t) - static void rspi_dma_complete(void *arg) { struct rspi_data *rspi = arg; @@ -617,8 +615,6 @@ static int qspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) return 0; } -#define receive_pio(spi, t) spi->ops->receive_pio(spi, t) - static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) { struct scatterlist sg, sg_dummy; @@ -743,7 +739,7 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, if (rspi_is_dma(rspi, xfer)) ret = rspi_send_dma(rspi, xfer); else - ret = send_pio(rspi, xfer); + ret = rspi_send_pio(rspi, xfer); if (ret < 0) return ret; } @@ -751,11 +747,27 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, if (rspi_is_dma(rspi, xfer)) ret = rspi_receive_dma(rspi, xfer); else - ret = receive_pio(rspi, xfer); + ret = rspi_receive_pio(rspi, xfer); } return ret; } +static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + int ret = 0; + + if (xfer->tx_buf) { + ret = qspi_send_pio(rspi, xfer); + if (ret < 0) + return ret; + } + if (xfer->rx_buf) + ret = qspi_receive_pio(rspi, xfer); + return ret; +} + static int rspi_setup(struct spi_device *spi) { struct rspi_data *rspi = spi_master_get_devdata(spi->master); @@ -948,7 +960,7 @@ static int rspi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->setup = rspi_setup; - master->transfer_one = rspi_transfer_one; + master->transfer_one = ops->transfer_one; master->cleanup = rspi_cleanup; master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; @@ -990,14 +1002,12 @@ error1: static struct spi_ops rspi_ops = { .set_config_register = rspi_set_config_register, - .send_pio = rspi_send_pio, - .receive_pio = rspi_receive_pio, + .transfer_one = rspi_transfer_one, }; static struct spi_ops qspi_ops = { .set_config_register = qspi_set_config_register, - .send_pio = qspi_send_pio, - .receive_pio = qspi_receive_pio, + .transfer_one = qspi_transfer_one, }; static struct platform_device_id spi_driver_ids[] = { From 8449fd76deb9ac67a15a6fb8ead7bb4595d019d2 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:56 +0100 Subject: [PATCH 006/201] spi: rspi: Merge rspi_send_pio() and rspi_receive_pio() rspi_send_pio() and rspi_receive_pio() are very similar: - the former only sends data, using TX Only Mode, - the latter sends and receives full duplex data to/from the hardware, but uses dummy transmit data. Merge them into rspi_transfer_out_in(), now supporting full duplex if needed. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 101 +++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 55 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index d837c5029308..cc90136d02c8 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -389,27 +389,6 @@ static int rspi_data_out_in(struct rspi_data *rspi, u8 data) return rspi_data_in(rspi); } -static int rspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) -{ - int remain = t->len, ret; - const u8 *data = t->tx_buf; - - while (remain > 0) { - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, - RSPI_SPCR); - - ret = rspi_data_out(rspi, *data++); - if (ret < 0) - return ret; - remain--; - } - - /* Waiting for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); - - return 0; -} - static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) { int remain = t->len, ret; @@ -563,28 +542,6 @@ static void rspi_receive_init(const struct rspi_data *rspi) RSPI_SPSR); } -static int rspi_receive_pio(struct rspi_data *rspi, struct spi_transfer *t) -{ - int remain = t->len, ret; - u8 *data = t->rx_buf; - - rspi_receive_init(rspi); - - while (remain > 0) { - rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, - RSPI_SPCR); - - /* dummy write data for generate clock */ - ret = rspi_data_out_in(rspi, DUMMY_DATA); - if (ret < 0) - return ret; - *data++ = ret; - remain--; - } - - return 0; -} - static void qspi_receive_init(const struct rspi_data *rspi) { u8 spsr; @@ -729,27 +686,61 @@ static int rspi_is_dma(const struct rspi_data *rspi, struct spi_transfer *t) return 0; } +static int rspi_transfer_out_in(struct rspi_data *rspi, + struct spi_transfer *xfer) +{ + int remain = xfer->len, ret; + const u8 *tx_buf = xfer->tx_buf; + u8 *rx_buf = xfer->rx_buf; + u8 spcr, data; + + rspi_receive_init(rspi); + + spcr = rspi_read8(rspi, RSPI_SPCR); + if (rx_buf) + spcr &= ~SPCR_TXMD; + else + spcr |= SPCR_TXMD; + rspi_write8(rspi, spcr, RSPI_SPCR); + + while (remain > 0) { + data = tx_buf ? *tx_buf++ : DUMMY_DATA; + ret = rspi_data_out(rspi, data); + if (ret < 0) + return ret; + if (rx_buf) { + ret = rspi_data_in(rspi); + if (ret < 0) + return ret; + *rx_buf++ = ret; + } + remain--; + } + + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { struct rspi_data *rspi = spi_master_get_devdata(master); - int ret = 0; + int ret; + + if (!rspi_is_dma(rspi, xfer)) + return rspi_transfer_out_in(rspi, xfer); if (xfer->tx_buf) { - if (rspi_is_dma(rspi, xfer)) - ret = rspi_send_dma(rspi, xfer); - else - ret = rspi_send_pio(rspi, xfer); + ret = rspi_send_dma(rspi, xfer); if (ret < 0) return ret; } - if (xfer->rx_buf) { - if (rspi_is_dma(rspi, xfer)) - ret = rspi_receive_dma(rspi, xfer); - else - ret = rspi_receive_pio(rspi, xfer); - } - return ret; + if (xfer->rx_buf) + return rspi_receive_dma(rspi, xfer); + + return 0; } static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, From 340a15e6f0d6cd436c55693f7328a1de02fcdb96 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:57 +0100 Subject: [PATCH 007/201] spi: rspi: Merge qspi_send_pio() and qspi_receive_pio() qspi_send_pio() and qspi_receive_pio() are very similar: they both send and receive full duplex data to/from the hardware, but ignore the data stream in the unused direction. Merge them into qspi_transfer_out_in(), now supporting real full duplex. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 79 +++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 51 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index cc90136d02c8..5d39cd3eba62 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -389,28 +389,6 @@ static int rspi_data_out_in(struct rspi_data *rspi, u8 data) return rspi_data_in(rspi); } -static int qspi_send_pio(struct rspi_data *rspi, struct spi_transfer *t) -{ - int remain = t->len, ret; - const u8 *data = t->tx_buf; - - rspi_write8(rspi, SPBFCR_TXRST, QSPI_SPBFCR); - rspi_write8(rspi, 0x00, QSPI_SPBFCR); - - while (remain > 0) { - /* dummy read */ - ret = rspi_data_out_in(rspi, *data++); - if (ret < 0) - return ret; - remain--; - } - - /* Waiting for the last transmission */ - rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); - - return 0; -} - static void rspi_dma_complete(void *arg) { struct rspi_data *rspi = arg; @@ -550,26 +528,7 @@ static void qspi_receive_init(const struct rspi_data *rspi) if (spsr & SPSR_SPRF) rspi_read_data(rspi); /* 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_transfer *t) -{ - int remain = t->len, ret; - u8 *data = t->rx_buf; - - qspi_receive_init(rspi); - - while (remain > 0) { - /* dummy write for generate clock */ - ret = rspi_data_out_in(rspi, DUMMY_DATA); - if (ret < 0) - return ret; - *data++ = ret; - remain--; - } - - return 0; + rspi_write8(rspi, 0, QSPI_SPBFCR); } static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) @@ -743,20 +702,38 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, return 0; } +static int qspi_transfer_out_in(struct rspi_data *rspi, + struct spi_transfer *xfer) +{ + int remain = xfer->len, ret; + const u8 *tx_buf = xfer->tx_buf; + u8 *rx_buf = xfer->rx_buf; + u8 data; + + qspi_receive_init(rspi); + + while (remain > 0) { + data = tx_buf ? *tx_buf++ : DUMMY_DATA; + ret = rspi_data_out_in(rspi, data); + if (ret < 0) + return ret; + if (rx_buf) + *rx_buf++ = ret; + remain--; + } + + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { struct rspi_data *rspi = spi_master_get_devdata(master); - int ret = 0; - if (xfer->tx_buf) { - ret = qspi_send_pio(rspi, xfer); - if (ret < 0) - return ret; - } - if (xfer->rx_buf) - ret = qspi_receive_pio(rspi, xfer); - return ret; + return qspi_transfer_out_in(rspi, xfer); } static int rspi_setup(struct spi_device *spi) From 9372220678cd4c62992f7637b2ee36b47fa58d37 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:58 +0100 Subject: [PATCH 008/201] spi: rspi: Add support for more than one interrupt Add support for multiple interrupts, based on the SDK reference code. This is needed for RZ/A1H, which supports 3 interrupts. When using multiple interrupts, they must be called "rx" (SPRI) and "tx" (SPTI). The error interrupt (SPEI) is not used, as it matters for slave mode only. When using a single interrupt, it may be called "mux". If it cannot be found, the first interrupt in the device's resources will be used. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 106 +++++++++++++++++++++++++++++++++-------- 1 file changed, 87 insertions(+), 19 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 5d39cd3eba62..d2ade5e09f58 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1,7 +1,7 @@ /* * SH RSPI driver * - * Copyright (C) 2012 Renesas Solutions Corp. + * Copyright (C) 2012, 2013 Renesas Solutions Corp. * * Based on spi-sh.c: * Copyright (C) 2011 Renesas Solutions Corp. @@ -183,12 +183,12 @@ struct rspi_data { struct clk *clk; u8 spsr; u16 spcmd; + int rx_irq, tx_irq; const struct spi_ops *ops; /* for dmaengine */ struct dma_chan *chan_tx; struct dma_chan *chan_rx; - int irq; unsigned dma_width_16bit:1; unsigned dma_callbacked:1; @@ -440,7 +440,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) struct scatterlist sg; const void *buf = NULL; struct dma_async_tx_descriptor *desc; - unsigned len; + unsigned int len; int ret = 0; if (rspi->dma_width_16bit) { @@ -478,7 +478,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be * called. So, this driver disables the IRQ while DMA transfer. */ - disable_irq(rspi->irq); + disable_irq(rspi->tx_irq); rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); rspi_enable_irq(rspi, SPCR_SPTIE); @@ -497,7 +497,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) ret = -ETIMEDOUT; rspi_disable_irq(rspi, SPCR_SPTIE); - enable_irq(rspi->irq); + enable_irq(rspi->tx_irq); end: rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); @@ -536,7 +536,7 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) struct scatterlist sg, sg_dummy; void *dummy = NULL, *rx_buf = NULL; struct dma_async_tx_descriptor *desc, *desc_dummy; - unsigned len; + unsigned int len; int ret = 0; if (rspi->dma_width_16bit) { @@ -594,7 +594,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be * called. So, this driver disables the IRQ while DMA transfer. */ - disable_irq(rspi->irq); + disable_irq(rspi->tx_irq); + if (rspi->rx_irq != rspi->tx_irq) + disable_irq(rspi->rx_irq); rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR); rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); @@ -617,7 +619,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) ret = -ETIMEDOUT; rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); - enable_irq(rspi->irq); + enable_irq(rspi->tx_irq); + if (rspi->rx_irq != rspi->tx_irq) + enable_irq(rspi->rx_irq); end: rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE); @@ -775,7 +779,7 @@ static int rspi_unprepare_message(struct spi_master *master, return 0; } -static irqreturn_t rspi_irq(int irq, void *_sr) +static irqreturn_t rspi_irq_mux(int irq, void *_sr) { struct rspi_data *rspi = _sr; u8 spsr; @@ -797,6 +801,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr) return ret; } +static irqreturn_t rspi_irq_rx(int irq, void *_sr) +{ + struct rspi_data *rspi = _sr; + u8 spsr; + + rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); + if (spsr & SPSR_SPRF) { + rspi_disable_irq(rspi, SPCR_SPRIE); + wake_up(&rspi->wait); + return IRQ_HANDLED; + } + + return 0; +} + +static irqreturn_t rspi_irq_tx(int irq, void *_sr) +{ + struct rspi_data *rspi = _sr; + u8 spsr; + + rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); + if (spsr & SPSR_SPTEF) { + rspi_disable_irq(rspi, SPCR_SPTIE); + wake_up(&rspi->wait); + return IRQ_HANDLED; + } + + return 0; +} + static int rspi_request_dma(struct rspi_data *rspi, struct platform_device *pdev) { @@ -868,12 +902,25 @@ static int rspi_remove(struct platform_device *pdev) return 0; } +static int rspi_request_irq(struct device *dev, unsigned int irq, + irq_handler_t handler, const char *suffix, + void *dev_id) +{ + const char *base = dev_name(dev); + size_t len = strlen(base) + strlen(suffix) + 2; + char *name = devm_kzalloc(dev, len, GFP_KERNEL); + if (!name) + return -ENOMEM; + snprintf(name, len, "%s:%s", base, suffix); + return devm_request_irq(dev, irq, handler, 0, name, dev_id); +} + static int rspi_probe(struct platform_device *pdev) { struct resource *res; struct spi_master *master; struct rspi_data *rspi; - int ret, irq; + int ret; char clk_name[16]; const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); const struct spi_ops *ops; @@ -886,12 +933,6 @@ static int rspi_probe(struct platform_device *pdev) return -ENODEV; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "platform_get_irq error\n"); - return -ENODEV; - } - master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); if (master == NULL) { dev_err(&pdev->dev, "spi_alloc_master error.\n"); @@ -934,14 +975,41 @@ static int rspi_probe(struct platform_device *pdev) master->unprepare_message = rspi_unprepare_message; master->mode_bits = SPI_CPHA | SPI_CPOL; - ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0, - dev_name(&pdev->dev), rspi); + ret = platform_get_irq_byname(pdev, "rx"); + if (ret < 0) { + ret = platform_get_irq_byname(pdev, "mux"); + if (ret < 0) + ret = platform_get_irq(pdev, 0); + if (ret >= 0) + rspi->rx_irq = rspi->tx_irq = ret; + } else { + rspi->rx_irq = ret; + ret = platform_get_irq_byname(pdev, "tx"); + if (ret >= 0) + rspi->tx_irq = ret; + } + if (ret < 0) { + dev_err(&pdev->dev, "platform_get_irq error\n"); + goto error2; + } + + if (rspi->rx_irq == rspi->tx_irq) { + /* Single multiplexed interrupt */ + ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux, + "mux", rspi); + } else { + /* Multi-interrupt mode, only SPRI and SPTI are used */ + ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx, + "rx", rspi); + if (!ret) + ret = rspi_request_irq(&pdev->dev, rspi->tx_irq, + rspi_irq_tx, "tx", rspi); + } if (ret < 0) { dev_err(&pdev->dev, "request_irq error\n"); goto error2; } - rspi->irq = irq; ret = rspi_request_dma(rspi, pdev); if (ret < 0) { dev_err(&pdev->dev, "rspi_request_dma failed.\n"); From 862d357f84f009fdcba22be8d6a2f82ff80ab740 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:43:59 +0100 Subject: [PATCH 009/201] spi: rspi: Add support for RSPI on RZ/A1H Add support for the RSPI variant in the RZ/A1H (r7s72100) SoC. Main differences with RSPI on SH are: - Lack of TX only mode, hence we always have to use full duplex transfers, - The Data Register must be accessed used 8-bit operations. RSPI on RZ is matched using the new "rspi-rz" platform device name. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 101 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index d2ade5e09f58..0c7556978d2e 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -47,7 +47,7 @@ #define RSPI_SPCKD 0x0c /* Clock Delay Register */ #define RSPI_SSLND 0x0d /* Slave Select Negation Delay Register */ #define RSPI_SPND 0x0e /* Next-Access Delay Register */ -#define RSPI_SPCR2 0x0f /* Control Register 2 */ +#define RSPI_SPCR2 0x0f /* Control Register 2 (SH only) */ #define RSPI_SPCMD0 0x10 /* Command Register 0 */ #define RSPI_SPCMD1 0x12 /* Command Register 1 */ #define RSPI_SPCMD2 0x14 /* Command Register 2 */ @@ -56,10 +56,12 @@ #define RSPI_SPCMD5 0x1a /* Command Register 5 */ #define RSPI_SPCMD6 0x1c /* Command Register 6 */ #define RSPI_SPCMD7 0x1e /* Command Register 7 */ + +/* RSPI on RZ only */ #define RSPI_SPBFCR 0x20 /* Buffer Control Register */ #define RSPI_SPBFDR 0x22 /* Buffer Data Count Setting Register */ -/*qspi only */ +/* QSPI only */ #define QSPI_SPBFCR 0x18 /* Buffer Control Register */ #define QSPI_SPBDCR 0x1a /* Buffer Data Count Register */ #define QSPI_SPBMUL0 0x1c /* Transfer Data Length Multiplier Setting Register 0 */ @@ -102,7 +104,7 @@ #define SPSR_PERF 0x08 /* Parity Error Flag */ #define SPSR_MODF 0x04 /* Mode Fault Error Flag */ #define SPSR_IDLNF 0x02 /* RSPI Idle Flag */ -#define SPSR_OVRF 0x01 /* Overrun Error Flag */ +#define SPSR_OVRF 0x01 /* Overrun Error Flag (RSPI only) */ /* SPSCR - Sequence Control Register */ #define SPSCR_SPSLN_MASK 0x07 /* Sequence Length Specification */ @@ -119,13 +121,13 @@ #define SPDCR_SPLWORD SPDCR_SPLW1 #define SPDCR_SPLBYTE SPDCR_SPLW0 #define SPDCR_SPLW 0x20 /* Access Width Specification (SH) */ -#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select */ +#define SPDCR_SPRDTD 0x10 /* Receive Transmit Data Select (SH) */ #define SPDCR_SLSEL1 0x08 #define SPDCR_SLSEL0 0x04 -#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select */ +#define SPDCR_SLSEL_MASK 0x0c /* SSL1 Output Select (SH) */ #define SPDCR_SPFC1 0x02 #define SPDCR_SPFC0 0x01 -#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) */ +#define SPDCR_SPFC_MASK 0x03 /* Frame Count Setting (1-4) (SH) */ /* SPCKD - Clock Delay Register */ #define SPCKD_SCKDL_MASK 0x07 /* Clock Delay Setting (1-8) */ @@ -168,8 +170,8 @@ #define SPCMD_CPHA 0x0001 /* Clock Phase Setting */ /* SPBFCR - Buffer Control Register */ -#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset (qspi only) */ -#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset (qspi only) */ +#define SPBFCR_TXRST 0x80 /* Transmit Buffer Data Reset */ +#define SPBFCR_RXRST 0x40 /* Receive Buffer Data Reset */ #define SPBFCR_TXTRG_MASK 0x30 /* Transmit Buffer Data Triggering Number */ #define SPBFCR_RXTRG_MASK 0x07 /* Receive Buffer Data Triggering Number */ @@ -244,7 +246,7 @@ struct spi_ops { }; /* - * functions for RSPI + * functions for RSPI on legacy SH */ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) { @@ -279,6 +281,39 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) return 0; } +/* + * functions for RSPI on RZ + */ +static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) +{ + int spbr; + + /* Sets output mode */ + 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); + + /* Disable dummy transmission, set byte access */ + rspi_write8(rspi, SPDCR_SPLBYTE, RSPI_SPDCR); + rspi->byte_access = 1; + + /* 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 SPCMD */ + rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size); + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); + + /* Sets RSPI mode */ + rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); + + return 0; +} + /* * functions for QSPI */ @@ -520,6 +555,13 @@ static void rspi_receive_init(const struct rspi_data *rspi) RSPI_SPSR); } +static void rspi_rz_receive_init(const struct rspi_data *rspi) +{ + rspi_receive_init(rspi); + rspi_write8(rspi, SPBFCR_TXRST | SPBFCR_RXRST, RSPI_SPBFCR); + rspi_write8(rspi, 0, RSPI_SPBFCR); +} + static void qspi_receive_init(const struct rspi_data *rspi) { u8 spsr; @@ -706,6 +748,41 @@ static int rspi_transfer_one(struct spi_master *master, struct spi_device *spi, return 0; } +static int rspi_rz_transfer_out_in(struct rspi_data *rspi, + struct spi_transfer *xfer) +{ + int remain = xfer->len, ret; + const u8 *tx_buf = xfer->tx_buf; + u8 *rx_buf = xfer->rx_buf; + u8 data; + + rspi_rz_receive_init(rspi); + + while (remain > 0) { + data = tx_buf ? *tx_buf++ : DUMMY_DATA; + ret = rspi_data_out_in(rspi, data); + if (ret < 0) + return ret; + if (rx_buf) + *rx_buf++ = ret; + remain--; + } + + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + +static int rspi_rz_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct rspi_data *rspi = spi_master_get_devdata(master); + + return rspi_rz_transfer_out_in(rspi, xfer); +} + static int qspi_transfer_out_in(struct rspi_data *rspi, struct spi_transfer *xfer) { @@ -1041,6 +1118,11 @@ static struct spi_ops rspi_ops = { .transfer_one = rspi_transfer_one, }; +static struct spi_ops rspi_rz_ops = { + .set_config_register = rspi_rz_set_config_register, + .transfer_one = rspi_rz_transfer_one, +}; + static struct spi_ops qspi_ops = { .set_config_register = qspi_set_config_register, .transfer_one = qspi_transfer_one, @@ -1048,6 +1130,7 @@ static struct spi_ops qspi_ops = { static struct platform_device_id spi_driver_ids[] = { { "rspi", (kernel_ulong_t)&rspi_ops }, + { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops }, { "qspi", (kernel_ulong_t)&qspi_ops }, {}, }; From 06a7a3cff042a36fb7e6af71039a17c6d1a6d90f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:44:00 +0100 Subject: [PATCH 010/201] spi: rspi: Add support for loopback mode Add support for specifying loopback mode. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 0c7556978d2e..28db8770aaf3 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -183,8 +183,9 @@ struct rspi_data { struct spi_master *master; wait_queue_head_t wait; struct clk *clk; - u8 spsr; u16 spcmd; + u8 spsr; + u8 sppcr; int rx_irq, tx_irq; const struct spi_ops *ops; @@ -252,8 +253,8 @@ 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 output mode, MOSI signal, and (optionally) loopback */ + rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; @@ -288,8 +289,8 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) { int spbr; - /* Sets output mode */ - rspi_write8(rspi, 0x00, RSPI_SPPCR); + /* Sets output mode, MOSI signal, and (optionally) loopback */ + rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz) - 1; @@ -322,8 +323,8 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) u16 spcmd; int spbr; - /* Sets output mode(CMOS) and MOSI signal(from previous transfer) */ - rspi_write8(rspi, 0x00, RSPI_SPPCR); + /* Sets output mode, MOSI signal, and (optionally) loopback */ + rspi_write8(rspi, rspi->sppcr, RSPI_SPPCR); /* Sets transfer bit rate */ spbr = clk_get_rate(rspi->clk) / (2 * rspi->max_speed_hz); @@ -829,6 +830,11 @@ static int rspi_setup(struct spi_device *spi) if (spi->mode & SPI_CPHA) rspi->spcmd |= SPCMD_CPHA; + /* CMOS output mode and MOSI signal from previous transfer */ + rspi->sppcr = 0; + if (spi->mode & SPI_LOOP) + rspi->sppcr |= SPPCR_SPLP; + set_config_register(rspi, 8); return 0; @@ -1050,7 +1056,7 @@ static int rspi_probe(struct platform_device *pdev) master->cleanup = rspi_cleanup; master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; - master->mode_bits = SPI_CPHA | SPI_CPOL; + master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP; ret = platform_get_irq_byname(pdev, "rx"); if (ret < 0) { From 17fe0d9a28fe742c467f800625459cf7bcb44b3b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:44:01 +0100 Subject: [PATCH 011/201] spi: rspi: Convert to clk_prepare_enable/disable_unprepare Get the driver ready for the migration to the common clock framework by calling clk_prepare_enable() and clk_disable_unprepare(). Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 28db8770aaf3..a648b40c271b 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -980,7 +980,7 @@ static int rspi_remove(struct platform_device *pdev) struct rspi_data *rspi = platform_get_drvdata(pdev); rspi_release_dma(rspi); - clk_disable(rspi->clk); + clk_disable_unprepare(rspi->clk); return 0; } @@ -1041,7 +1041,12 @@ static int rspi_probe(struct platform_device *pdev) ret = PTR_ERR(rspi->clk); goto error1; } - clk_enable(rspi->clk); + + ret = clk_prepare_enable(rspi->clk); + if (ret < 0) { + dev_err(&pdev->dev, "unable to prepare/enable clock\n"); + goto error1; + } init_waitqueue_head(&rspi->wait); @@ -1112,7 +1117,7 @@ static int rspi_probe(struct platform_device *pdev) error3: rspi_release_dma(rspi); error2: - clk_disable(rspi->clk); + clk_disable_unprepare(rspi->clk); error1: spi_master_put(master); From 29f397b739ceef90c8b848f6579cbacd088e896e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 24 Jan 2014 09:44:02 +0100 Subject: [PATCH 012/201] spi: rspi: Use NULL as the clock ID There's only one RSPI/QSPI clock, so we can use NULL as the clock ID Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index a648b40c271b..d79a7ed9b92e 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1004,7 +1004,6 @@ static int rspi_probe(struct platform_device *pdev) struct spi_master *master; struct rspi_data *rspi; int ret; - char clk_name[16]; const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); const struct spi_ops *ops; const struct platform_device_id *id_entry = pdev->id_entry; @@ -1034,8 +1033,7 @@ static int rspi_probe(struct platform_device *pdev) goto error1; } - snprintf(clk_name, sizeof(clk_name), "%s%d", id_entry->name, pdev->id); - rspi->clk = devm_clk_get(&pdev->dev, clk_name); + rspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(rspi->clk)) { dev_err(&pdev->dev, "cannot get clock\n"); ret = PTR_ERR(rspi->clk); From 426ef76dd8a394a0e04d096941cd9acb49539a3e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 28 Jan 2014 10:21:38 +0100 Subject: [PATCH 013/201] spi: rspi: Add DT support Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-rspi.txt | 59 ++++++++++ drivers/spi/spi-rspi.c | 106 +++++++++++++----- 2 files changed, 136 insertions(+), 29 deletions(-) create mode 100644 Documentation/devicetree/bindings/spi/spi-rspi.txt diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt new file mode 100644 index 000000000000..95f9b21d239f --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt @@ -0,0 +1,59 @@ +Device tree configuration for Renesas RSPI/QSPI driver + +Required properties: +- compatible : For Renesas Serial Peripheral Interface on legacy SH: + "renesas,rspi-", "renesas,rspi" as fallback. + For Renesas Serial Peripheral Interface on RZ/A1H: + "renesas,rspi-", "renesas,rspi-rz" as fallback. + For Quad Serial Peripheral Interface on R-Car Gen2: + "renesas,qspi-", "renesas,qspi" as fallback. + Examples of valid soctypes are "sh7757" (SH), + "r7s72100" (RZ/A1H), "r8a7790" (R-Car H2), and + "r8a7791" (R-Car M2). +- reg : Address start and address range size of the device +- interrupts : A list of interrupt-specifiers, one for each entry in + interrupt-names. + If interrupt-names is not present, an interrupt specifier + for a single muxed interrupt. +- interrupt-names : A list of interrupt names. Should contain (if present): + - "error" for SPEI, + - "rx" for SPRI, + - "tx" to SPTI, + - "mux" for a single muxed interrupt. +- interrupt-parent : The phandle for the interrupt controller that + services interrupts for this device. +- num-cs : Number of chip selects. Some RSPI cores have more than 1. +- #address-cells : Must be <1> +- #size-cells : Must be <0> + +Optional properties: +- clocks: : Must contain a reference to the functional clock. + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. + +Examples: + + spi0: spi@e800c800 { + compatible = "renesas,rspi-r7s72100", "renesas,rspi-rz"; + reg = <0xe800c800 0x24>; + interrupts = <0 238 IRQ_TYPE_LEVEL_HIGH>, + <0 239 IRQ_TYPE_LEVEL_HIGH>, + <0 240 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "error", "rx", "tx"; + interrupt-parent = <&gic>; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi: spi@e6b10000 { + compatible = "renesas,qspi-r8a7791", "renesas,qspi"; + reg = <0 0xe6b10000 0 0x2c>; + interrupt-parent = <&gic>; + interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp9_clks R8A7791_CLK_QSPI_MOD>; + num-cs = <1>; + #address-cells = <1>; + #size-cells = <0>; + }; diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index d79a7ed9b92e..e56fcb5f7f99 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -985,6 +986,56 @@ static int rspi_remove(struct platform_device *pdev) return 0; } +static const struct spi_ops rspi_ops = { + .set_config_register = rspi_set_config_register, + .transfer_one = rspi_transfer_one, +}; + +static const struct spi_ops rspi_rz_ops = { + .set_config_register = rspi_rz_set_config_register, + .transfer_one = rspi_rz_transfer_one, +}; + +static const struct spi_ops qspi_ops = { + .set_config_register = qspi_set_config_register, + .transfer_one = qspi_transfer_one, +}; + +#ifdef CONFIG_OF +static const struct of_device_id rspi_of_match[] = { + /* RSPI on legacy SH */ + { .compatible = "renesas,rspi", .data = &rspi_ops }, + /* RSPI on RZ/A1H */ + { .compatible = "renesas,rspi-rz", .data = &rspi_rz_ops }, + /* QSPI on R-Car Gen2 */ + { .compatible = "renesas,qspi", .data = &qspi_ops }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, rspi_of_match); + +static int rspi_parse_dt(struct device *dev, struct spi_master *master) +{ + u32 num_cs; + int error; + + /* Parse DT properties */ + error = of_property_read_u32(dev->of_node, "num-cs", &num_cs); + if (error) { + dev_err(dev, "of_property_read_u32 num-cs failed %d\n", error); + return error; + } + + master->num_chipselect = num_cs; + return 0; +} +#else +static inline int rspi_parse_dt(struct device *dev, struct spi_master *master) +{ + return -EINVAL; +} +#endif /* CONFIG_OF */ + static int rspi_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, const char *suffix, void *dev_id) @@ -1004,16 +1055,9 @@ static int rspi_probe(struct platform_device *pdev) struct spi_master *master; struct rspi_data *rspi; int ret; - const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); + const struct of_device_id *of_id; + const struct rspi_plat_data *rspi_pd; 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; - } master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); if (master == NULL) { @@ -1021,6 +1065,28 @@ static int rspi_probe(struct platform_device *pdev) return -ENOMEM; } + of_id = of_match_device(rspi_of_match, &pdev->dev); + if (of_id) { + ops = of_id->data; + ret = rspi_parse_dt(&pdev->dev, master); + if (ret) + goto error1; + } else { + ops = (struct spi_ops *)pdev->id_entry->driver_data; + rspi_pd = dev_get_platdata(&pdev->dev); + if (rspi_pd && rspi_pd->num_chipselect) + master->num_chipselect = rspi_pd->num_chipselect; + else + master->num_chipselect = 2; /* default */ + }; + + /* ops parameter check */ + if (!ops->set_config_register) { + dev_err(&pdev->dev, "there is no set_config_register\n"); + ret = -ENODEV; + goto error1; + } + rspi = spi_master_get_devdata(master); platform_set_drvdata(pdev, rspi); rspi->ops = ops; @@ -1048,11 +1114,6 @@ static int rspi_probe(struct platform_device *pdev) init_waitqueue_head(&rspi->wait); - if (rspi_pd && rspi_pd->num_chipselect) - master->num_chipselect = rspi_pd->num_chipselect; - else - master->num_chipselect = 2; /* default */ - master->bus_num = pdev->id; master->setup = rspi_setup; master->transfer_one = ops->transfer_one; @@ -1060,6 +1121,7 @@ static int rspi_probe(struct platform_device *pdev) master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP; + master->dev.of_node = pdev->dev.of_node; ret = platform_get_irq_byname(pdev, "rx"); if (ret < 0) { @@ -1122,21 +1184,6 @@ error1: return ret; } -static struct spi_ops rspi_ops = { - .set_config_register = rspi_set_config_register, - .transfer_one = rspi_transfer_one, -}; - -static struct spi_ops rspi_rz_ops = { - .set_config_register = rspi_rz_set_config_register, - .transfer_one = rspi_rz_transfer_one, -}; - -static struct spi_ops qspi_ops = { - .set_config_register = qspi_set_config_register, - .transfer_one = qspi_transfer_one, -}; - static struct platform_device_id spi_driver_ids[] = { { "rspi", (kernel_ulong_t)&rspi_ops }, { "rspi-rz", (kernel_ulong_t)&rspi_rz_ops }, @@ -1153,6 +1200,7 @@ static struct platform_driver rspi_driver = { .driver = { .name = "renesas_spi", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(rspi_of_match), }, }; module_platform_driver(rspi_driver); From 880c6d114fd79a6973708744c78c7f55da6aea4c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 30 Jan 2014 09:43:50 +0100 Subject: [PATCH 014/201] spi: rspi: Add support for Quad and Dual SPI Transfers on QSPI Add support for Quad and Dual SPI Transfers on the Renesas Quad Serial Peripheral Interface, as found in R-Car Gen2 SoCs like R-Car H2 (r8a7790) and R-Car M2 (r8a7791): - Add unidirectional transfer methods for Quad/Dual SPI Transfers. - Program the sequencer to handle SPI messages with multiple transfer modes when Quad or Dual transfers are enabled for an SPI slave. Up to 4 transfer modes per SPI message are supported by the hardware. - Advertise the availability of Quad and Dual SPI modes on QSPI. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 162 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 148 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index e56fcb5f7f99..34ad4bca8a41 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -2,6 +2,7 @@ * SH RSPI driver * * Copyright (C) 2012, 2013 Renesas Solutions Corp. + * Copyright (C) 2014 Glider bvba * * Based on spi-sh.c: * Copyright (C) 2011 Renesas Solutions Corp. @@ -57,6 +58,10 @@ #define RSPI_SPCMD5 0x1a /* Command Register 5 */ #define RSPI_SPCMD6 0x1c /* Command Register 6 */ #define RSPI_SPCMD7 0x1e /* Command Register 7 */ +#define RSPI_SPCMD(i) (RSPI_SPCMD0 + (i) * 2) +#define RSPI_NUM_SPCMD 8 +#define RSPI_RZ_NUM_SPCMD 4 +#define QSPI_NUM_SPCMD 4 /* RSPI on RZ only */ #define RSPI_SPBFCR 0x20 /* Buffer Control Register */ @@ -69,6 +74,7 @@ #define QSPI_SPBMUL1 0x20 /* Transfer Data Length Multiplier Setting Register 1 */ #define QSPI_SPBMUL2 0x24 /* Transfer Data Length Multiplier Setting Register 2 */ #define QSPI_SPBMUL3 0x28 /* Transfer Data Length Multiplier Setting Register 3 */ +#define QSPI_SPBMUL(i) (QSPI_SPBMUL0 + (i) * 4) /* SPCR - Control Register */ #define SPCR_SPRIE 0x80 /* Receive Interrupt Enable */ @@ -152,7 +158,7 @@ #define SPCMD_LSBF 0x1000 /* LSB First */ #define SPCMD_SPB_MASK 0x0f00 /* Data Length Setting */ #define SPCMD_SPB_8_TO_16(bit) (((bit - 1) << 8) & SPCMD_SPB_MASK) -#define SPCMD_SPB_8BIT 0x0000 /* qspi only */ +#define SPCMD_SPB_8BIT 0x0000 /* QSPI only */ #define SPCMD_SPB_16BIT 0x0100 #define SPCMD_SPB_20BIT 0x0000 #define SPCMD_SPB_24BIT 0x0100 @@ -245,6 +251,7 @@ struct spi_ops { int (*set_config_register)(struct rspi_data *rspi, int access_size); int (*transfer_one)(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer); + u16 mode_bits; }; /* @@ -274,8 +281,8 @@ static int rspi_set_config_register(struct rspi_data *rspi, int access_size) rspi_write8(rspi, 0x00, RSPI_SPCR2); /* Sets SPCMD */ - rspi_write16(rspi, SPCMD_SPB_8_TO_16(access_size) | rspi->spcmd, - RSPI_SPCMD0); + rspi->spcmd |= SPCMD_SPB_8_TO_16(access_size); + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); /* Sets RSPI mode */ rspi_write8(rspi, SPCR_MSTR, RSPI_SPCR); @@ -321,7 +328,6 @@ static int rspi_rz_set_config_register(struct rspi_data *rspi, int access_size) */ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) { - u16 spcmd; int spbr; /* Sets output mode, MOSI signal, and (optionally) loopback */ @@ -342,13 +348,13 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) /* Data Length Setting */ if (access_size == 8) - spcmd = SPCMD_SPB_8BIT; + rspi->spcmd |= SPCMD_SPB_8BIT; else if (access_size == 16) - spcmd = SPCMD_SPB_16BIT; + rspi->spcmd |= SPCMD_SPB_16BIT; else - spcmd = SPCMD_SPB_32BIT; + rspi->spcmd |= SPCMD_SPB_32BIT; - spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | rspi->spcmd | SPCMD_SPNDEN; + rspi->spcmd |= SPCMD_SCKDEN | SPCMD_SLNDEN | SPCMD_SPNDEN; /* Resets transfer data length */ rspi_write32(rspi, 0, QSPI_SPBMUL0); @@ -359,9 +365,9 @@ static int qspi_set_config_register(struct rspi_data *rspi, int access_size) rspi_write8(rspi, 0x00, QSPI_SPBFCR); /* Sets SPCMD */ - rspi_write16(rspi, spcmd, RSPI_SPCMD0); + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); - /* Enables SPI function in a master mode */ + /* Enables SPI function in master mode */ rspi_write8(rspi, SPCR_SPE | SPCR_MSTR, RSPI_SPCR); return 0; @@ -811,12 +817,55 @@ static int qspi_transfer_out_in(struct rspi_data *rspi, return 0; } +static int qspi_transfer_out(struct rspi_data *rspi, struct spi_transfer *xfer) +{ + const u8 *buf = xfer->tx_buf; + unsigned int i; + int ret; + + for (i = 0; i < xfer->len; i++) { + ret = rspi_data_out(rspi, *buf++); + if (ret < 0) + return ret; + } + + /* Wait for the last transmission */ + rspi_wait_for_interrupt(rspi, SPSR_SPTEF, SPCR_SPTIE); + + return 0; +} + +static int qspi_transfer_in(struct rspi_data *rspi, struct spi_transfer *xfer) +{ + u8 *buf = xfer->rx_buf; + unsigned int i; + int ret; + + for (i = 0; i < xfer->len; i++) { + ret = rspi_data_in(rspi); + if (ret < 0) + return ret; + *buf++ = ret; + } + + return 0; +} + static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) { struct rspi_data *rspi = spi_master_get_devdata(master); - return qspi_transfer_out_in(rspi, xfer); + if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) { + /* Quad or Dual SPI Write */ + return qspi_transfer_out(rspi, xfer); + } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) { + /* Quad or Dual SPI Read */ + return qspi_transfer_in(rspi, xfer); + } else { + /* Single SPI Transfer */ + return qspi_transfer_out_in(rspi, xfer); + } } static int rspi_setup(struct spi_device *spi) @@ -845,21 +894,101 @@ static void rspi_cleanup(struct spi_device *spi) { } +static u16 qspi_transfer_mode(const struct spi_transfer *xfer) +{ + if (xfer->tx_buf) + switch (xfer->tx_nbits) { + case SPI_NBITS_QUAD: + return SPCMD_SPIMOD_QUAD; + case SPI_NBITS_DUAL: + return SPCMD_SPIMOD_DUAL; + default: + return 0; + } + if (xfer->rx_buf) + switch (xfer->rx_nbits) { + case SPI_NBITS_QUAD: + return SPCMD_SPIMOD_QUAD | SPCMD_SPRW; + case SPI_NBITS_DUAL: + return SPCMD_SPIMOD_DUAL | SPCMD_SPRW; + default: + return 0; + } + + return 0; +} + +static int qspi_setup_sequencer(struct rspi_data *rspi, + const struct spi_message *msg) +{ + const struct spi_transfer *xfer; + unsigned int i = 0, len = 0; + u16 current_mode = 0xffff, mode; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + mode = qspi_transfer_mode(xfer); + if (mode == current_mode) { + len += xfer->len; + continue; + } + + /* Transfer mode change */ + if (i) { + /* Set transfer data length of previous transfer */ + rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); + } + + if (i >= QSPI_NUM_SPCMD) { + dev_err(&msg->spi->dev, + "Too many different transfer modes"); + return -EINVAL; + } + + /* Program transfer mode for this transfer */ + rspi_write16(rspi, rspi->spcmd | mode, RSPI_SPCMD(i)); + current_mode = mode; + len = xfer->len; + i++; + } + if (i) { + /* Set final transfer data length and sequence length */ + rspi_write32(rspi, len, QSPI_SPBMUL(i - 1)); + rspi_write8(rspi, i - 1, RSPI_SPSCR); + } + + return 0; +} + static int rspi_prepare_message(struct spi_master *master, - struct spi_message *message) + struct spi_message *msg) { struct rspi_data *rspi = spi_master_get_devdata(master); + int ret; + if (msg->spi->mode & + (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)) { + /* Setup sequencer for messages with multiple transfer modes */ + ret = qspi_setup_sequencer(rspi, msg); + if (ret < 0) + return ret; + } + + /* Enable SPI function in master mode */ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_SPE, RSPI_SPCR); return 0; } static int rspi_unprepare_message(struct spi_master *master, - struct spi_message *message) + struct spi_message *msg) { struct rspi_data *rspi = spi_master_get_devdata(master); + /* Disable SPI function */ rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_SPE, RSPI_SPCR); + + /* Reset sequencer for Single SPI Transfers */ + rspi_write16(rspi, rspi->spcmd, RSPI_SPCMD0); + rspi_write8(rspi, 0, RSPI_SPSCR); return 0; } @@ -989,16 +1118,21 @@ static int rspi_remove(struct platform_device *pdev) static const struct spi_ops rspi_ops = { .set_config_register = rspi_set_config_register, .transfer_one = rspi_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, }; static const struct spi_ops rspi_rz_ops = { .set_config_register = rspi_rz_set_config_register, .transfer_one = rspi_rz_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP, }; static const struct spi_ops qspi_ops = { .set_config_register = qspi_set_config_register, .transfer_one = qspi_transfer_one, + .mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP | + SPI_TX_DUAL | SPI_TX_QUAD | + SPI_RX_DUAL | SPI_RX_QUAD, }; #ifdef CONFIG_OF @@ -1120,7 +1254,7 @@ static int rspi_probe(struct platform_device *pdev) master->cleanup = rspi_cleanup; master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; - master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LOOP; + master->mode_bits = ops->mode_bits; master->dev.of_node = pdev->dev.of_node; ret = platform_get_irq_byname(pdev, "rx"); From 2418991efb7b1f9fc574771450ac17689682b3f6 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 26 Jan 2014 10:14:32 +0200 Subject: [PATCH 015/201] spi: dw-mmio: allow multiple instances Use the platform_device id to uniquely identify each SPI master instance. Cc: Jean-Hugues Deschenes Signed-off-by: Baruch Siach Signed-off-by: Mark Brown --- drivers/spi/spi-dw-mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-dw-mmio.c b/drivers/spi/spi-dw-mmio.c index 9af56cdf1540..1492f5ee9aaa 100644 --- a/drivers/spi/spi-dw-mmio.c +++ b/drivers/spi/spi-dw-mmio.c @@ -66,7 +66,7 @@ static int dw_spi_mmio_probe(struct platform_device *pdev) if (ret) return ret; - dws->bus_num = 0; + dws->bus_num = pdev->id; dws->num_cs = 4; dws->max_freq = clk_get_rate(dwsmmio->clk); From 794f61a30e115f44821d8c3cf812a969be48a8a5 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Fri, 31 Jan 2014 12:07:48 +0200 Subject: [PATCH 016/201] spi: dw-mmio: remove HAVE_CLK build dependecy Since 93abe8e4 (clk: add non CONFIG_HAVE_CLK routines) code using clk.h like this platform driver needs not depend on HAVE_CLK. Signed-off-by: Baruch Siach Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..b1fc8eb64f7e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -546,7 +546,7 @@ config SPI_DW_MID_DMA config SPI_DW_MMIO tristate "Memory-mapped io interface driver for DW SPI core" - depends on SPI_DESIGNWARE && HAVE_CLK + depends on SPI_DESIGNWARE # # There are lots of SPI device types, with sensors and memory From 3a44623d5e1404b29786f1afd225d1aa04a4ae90 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 21 Jan 2014 16:22:47 -0500 Subject: [PATCH 017/201] spi: delete non-required instances of include None of these files are actually using any __init type directives and hence don't need to include . Most are just a left over from __devinit and __cpuinit removal, or simply due to code getting copied from one driver to the next. Signed-off-by: Paul Gortmaker Signed-off-by: Mark Brown --- drivers/spi/spi-altera.c | 1 - drivers/spi/spi-ath79.c | 1 - drivers/spi/spi-atmel.c | 1 - drivers/spi/spi-bcm63xx.c | 1 - drivers/spi/spi-bfin-sport.c | 1 - drivers/spi/spi-bitbang.c | 1 - drivers/spi/spi-clps711x.c | 1 - drivers/spi/spi-gpio.c | 1 - drivers/spi/spi-imx.c | 1 - drivers/spi/spi-mpc512x-psc.c | 1 - drivers/spi/spi-mpc52xx-psc.c | 1 - drivers/spi/spi-mpc52xx.c | 1 - drivers/spi/spi-mxs.c | 1 - drivers/spi/spi-nuc900.c | 1 - drivers/spi/spi-oc-tiny.c | 1 - drivers/spi/spi-octeon.c | 1 - drivers/spi/spi-omap2-mcspi.c | 1 - drivers/spi/spi-orion.c | 1 - drivers/spi/spi-ppc4xx.c | 1 - drivers/spi/spi-pxa2xx-dma.c | 1 - drivers/spi/spi-pxa2xx-pxadma.c | 1 - drivers/spi/spi-s3c24xx.c | 1 - drivers/spi/spi-sh-msiof.c | 1 - drivers/spi/spi-sh-sci.c | 1 - drivers/spi/spi-tegra114.c | 1 - drivers/spi/spi-tegra20-sflash.c | 1 - drivers/spi/spi-tegra20-slink.c | 1 - drivers/spi/spi-xcomm.c | 1 - drivers/spi/spi-xilinx.c | 1 - 29 files changed, 29 deletions(-) diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 5d7deaf62867..1928b835e870 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -13,7 +13,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/spi/spi-ath79.c b/drivers/spi/spi-ath79.c index 31534b51715a..a1cf9af9c0ad 100644 --- a/drivers/spi/spi-ath79.c +++ b/drivers/spi/spi-ath79.c @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index b0842f751016..88796dfe1c21 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 77286aef2adf..9e9ee5f08647 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -20,7 +20,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-bfin-sport.c b/drivers/spi/spi-bfin-sport.c index 38941e5920b5..f515c5e9db57 100644 --- a/drivers/spi/spi-bfin-sport.c +++ b/drivers/spi/spi-bfin-sport.c @@ -8,7 +8,6 @@ * Licensed under the GPL-2 or later. */ -#include #include #include #include diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index bd222f6b677d..3bfdb851960b 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -16,7 +16,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 374ba4a48a9e..bee864de5305 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -11,7 +11,6 @@ #include #include -#include #include #include #include diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 7beeb29472ac..cfc9fb3048d8 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -19,7 +19,6 @@ */ #include #include -#include #include #include #include diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index a5474ef9d2a0..8a77b7bd380c 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 5032141eeeec..56cead98e7a5 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include diff --git a/drivers/spi/spi-mpc52xx-psc.c b/drivers/spi/spi-mpc52xx-psc.c index 00ba910ab302..3d18d9351185 100644 --- a/drivers/spi/spi-mpc52xx-psc.c +++ b/drivers/spi/spi-mpc52xx-psc.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 7c675fe83101..f573c3c09968 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -12,7 +12,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 79e5aa2250c8..17bb9a9285ab 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -29,7 +29,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 50406306bc20..8181c69f15db 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index f7c896e2981e..022774e158f1 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -15,7 +15,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 67249a48b391..5665ae9ed92f 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index a72127f08e39..94f133cb2770 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -22,7 +22,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 7f2121fe2622..a362425400ea 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -9,7 +9,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/spi/spi-ppc4xx.c b/drivers/spi/spi-ppc4xx.c index 5ee56726f8d0..80b8408ac3e3 100644 --- a/drivers/spi/spi-ppc4xx.c +++ b/drivers/spi/spi-ppc4xx.c @@ -24,7 +24,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c index 3c0b55125f1e..713af4806f26 100644 --- a/drivers/spi/spi-pxa2xx-dma.c +++ b/drivers/spi/spi-pxa2xx-dma.c @@ -9,7 +9,6 @@ * published by the Free Software Foundation. */ -#include #include #include #include diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c index 2916efc7cfe5..e8a26f25d5c0 100644 --- a/drivers/spi/spi-pxa2xx-pxadma.c +++ b/drivers/spi/spi-pxa2xx-pxadma.c @@ -18,7 +18,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include #include #include diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 746424aa5353..c20df45204e2 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -9,7 +9,6 @@ * */ -#include #include #include #include diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 81cc02f5f9b0..33474061b742 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 38eb24df796c..85c2efd57c80 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 413c71843492..3f61bbf643e2 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 08794977f21a..18037ab646d6 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index be3a069879c3..8d62710d587e 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 24c40b13dab1..350a76b7e8d4 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -8,7 +8,6 @@ */ #include -#include #include #include #include diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 6d4ce4615163..e6cd1112ae40 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -14,7 +14,6 @@ */ #include -#include #include #include #include From 0a4e210e9965de3812df079fc70a702afc4445d2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jan 2014 13:22:17 +0800 Subject: [PATCH 018/201] spi: octeon: Use list_is_last() instead of open-coded Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-octeon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 67249a48b391..862ef30853d3 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -179,7 +179,8 @@ static int octeon_spi_transfer_one_message(struct spi_master *master, } list_for_each_entry(xfer, &msg->transfers, transfer_list) { - bool last_xfer = &xfer->transfer_list == msg->transfers.prev; + bool last_xfer = list_is_last(&xfer->transfer_list, + &msg->transfers); int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer); if (r < 0) { status = r; From 3e7dde425dbcc7965398e92909d898c4ebc9fdb8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 22 Jan 2014 18:41:36 +0000 Subject: [PATCH 019/201] spi/pl022: Unprepare clocks while suspended When the driver was converted to clk_prepare() the suspend path didn't have any changes made so the clock remains prepared throughout the runtime of the driver. Unprepare it when suspended so that any savings that can be made as a result are made. Signed-off-by: Mark Brown Acked-by: Linus Walleij --- drivers/spi/spi-pl022.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 2789b452e711..4ec49eae6141 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2296,7 +2296,7 @@ pl022_remove(struct amba_device *adev) */ static void pl022_suspend_resources(struct pl022 *pl022, bool runtime) { - clk_disable(pl022->clk); + clk_disable_unprepare(pl022->clk); if (runtime) pinctrl_pm_select_idle_state(&pl022->adev->dev); @@ -2312,7 +2312,7 @@ static void pl022_resume_resources(struct pl022 *pl022, bool runtime) /* Then let's idle the pins until the next transfer happens */ pinctrl_pm_select_idle_state(&pl022->adev->dev); - clk_enable(pl022->clk); + clk_prepare_enable(pl022->clk); } #endif From 589f6a90e6c5cda51ecb89799c5bff4074e9ef77 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 20 Jan 2014 23:18:45 +0800 Subject: [PATCH 020/201] spi: sc18is602: Remove sc18is602_setup() because it is done by spi core The checking for spi->mode is done in the implementation of spi_setup(). Calling sc18is602_check_transfer(spi, NULL, 0) is pointless because the code is equivent to checking if spi->max_speed_hz is 0. Note, sc18is602_check_transfer actually allows spi->max_speed_hz is 0 if t->speed_hz is set. So return error in sc18is602_setup() when spi->max_speed_hz is 0 does not make sense. Signed-off-by: Axel Lin Acked-by: Guenter Roeck Signed-off-by: Mark Brown --- drivers/spi/spi-sc18is602.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 121c2e1dea36..b3ac776def9b 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -245,14 +245,6 @@ error: return status; } -static int sc18is602_setup(struct spi_device *spi) -{ - if (spi->mode & ~(SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST)) - return -EINVAL; - - return sc18is602_check_transfer(spi, NULL, 0); -} - static int sc18is602_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -306,7 +298,6 @@ static int sc18is602_probe(struct i2c_client *client, master->bus_num = client->adapter->nr; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; master->bits_per_word_mask = SPI_BPW_MASK(8); - master->setup = sc18is602_setup; master->transfer_one_message = sc18is602_transfer_one; master->dev.of_node = np; From 8c328a262f513c042f97fcd2f2797a6d69fc0773 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jan 2014 17:07:43 +0800 Subject: [PATCH 021/201] spi: sirf: Avoid duplicate code in various bits_per_word cases Trivial cleanup to avoid duplicate code in various bits_per_word cases. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index e430689c3837..632d2b5b821f 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -459,11 +459,6 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_8; sspi->rx_word = spi_sirfsoc_rx_word_u8; sspi->tx_word = spi_sirfsoc_tx_word_u8; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_BYTE; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_BYTE; - sspi->word_width = 1; break; case 12: case 16: @@ -471,26 +466,22 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) SIRFSOC_SPI_TRAN_DAT_FORMAT_16; sspi->rx_word = spi_sirfsoc_rx_word_u16; sspi->tx_word = spi_sirfsoc_tx_word_u16; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_WORD; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_WORD; - sspi->word_width = 2; break; case 32: regval |= SIRFSOC_SPI_TRAN_DAT_FORMAT_32; sspi->rx_word = spi_sirfsoc_rx_word_u32; sspi->tx_word = spi_sirfsoc_tx_word_u32; - txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_DWORD; - rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | - SIRFSOC_SPI_FIFO_WIDTH_DWORD; - sspi->word_width = 4; break; default: BUG(); } + sspi->word_width = DIV_ROUND_UP(bits_per_word, 8); + txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + sspi->word_width; + rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | + sspi->word_width; + if (!(spi->mode & SPI_CS_HIGH)) regval |= SIRFSOC_SPI_CS_IDLE_STAT; if (!(spi->mode & SPI_LSB_FIRST)) From 971e9084beb50c0b244ff95ef2d888f7d158b8a8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jan 2014 14:07:04 +0800 Subject: [PATCH 022/201] spi: tegra114: Use list_is_last() instead of open-coded For better readability, and then we can remove the comment for last transfer. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 413c71843492..ead3ae89a08f 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -853,8 +853,8 @@ complete_xfer: SPI_COMMAND1); tegra_spi_transfer_delay(xfer->delay_usecs); goto exit; - } else if (msg->transfers.prev == &xfer->transfer_list) { - /* This is the last transfer in message */ + } else if (list_is_last(&xfer->transfer_list, + &msg->transfers)) { if (xfer->cs_change) tspi->cs_control = spi; else { From 16a0ce4e10edfe376b3071f161c71c4160c89d6b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 30 Jan 2014 22:16:41 +0000 Subject: [PATCH 023/201] spi: Add a timeout when waiting for transfers Don't wait indefinitely for transfers to complete but time out after 10ms more than we expect the transfer to take on the wire. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 23756b0f9036..516643d243c6 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -594,6 +594,7 @@ static int spi_transfer_one_message(struct spi_master *master, bool cur_cs = true; bool keep_cs = false; int ret = 0; + int ms = 1; spi_set_cs(msg->spi, true); @@ -611,7 +612,16 @@ static int spi_transfer_one_message(struct spi_master *master, if (ret > 0) { ret = 0; - wait_for_completion(&master->xfer_completion); + ms = xfer->len * 8 * 1000 / xfer->speed_hz; + ms += 10; /* some tolerance */ + + ms = wait_for_completion_timeout(&master->xfer_completion, + msecs_to_jiffies(ms)); + } + + if (ms == 0) { + dev_err(&msg->spi->dev, "SPI transfer timed out\n"); + msg->status = -ETIMEDOUT; } trace_spi_transfer_stop(msg, xfer); From 99adef310f682d6343cb40c1f6c9c25a4b3a450d Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Jan 2014 12:22:43 +0000 Subject: [PATCH 024/201] spi: Provide core support for DMA mapping transfers The process of DMA mapping buffers for SPI transfers does not vary between devices so in order to save duplication of code in drivers this can be factored out into the core, allowing it to be integrated with the work that is being done on factoring out the common elements from the data path including more sharing of dmaengine code. In order to use this masters need to provide a can_dma() operation and while the hardware is prepared they should ensure that DMA channels are provided in tx_dma and rx_dma. The core will then ensure that the buffers are mapped for DMA prior to calling transfer_one_message(). Currently the cleanup on error is not complete, this needs to be improved. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 82 +++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 18 +++++++++ 2 files changed, 100 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 23756b0f9036..bcdaa74f1c8e 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -580,6 +582,77 @@ static void spi_set_cs(struct spi_device *spi, bool enable) spi->master->set_cs(spi, !enable); } +static int spi_map_msg(struct spi_master *master, struct spi_message *msg) +{ + struct device *dev = master->dev.parent; + struct device *tx_dev, *rx_dev; + struct spi_transfer *xfer; + + if (msg->is_dma_mapped || !master->can_dma) + return 0; + + tx_dev = &master->dma_tx->dev->device; + rx_dev = &master->dma_rx->dev->device; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (!master->can_dma(master, msg->spi, xfer)) + continue; + + if (xfer->tx_buf != NULL) { + xfer->tx_dma = dma_map_single(tx_dev, + (void *)xfer->tx_buf, + xfer->len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, xfer->tx_dma)) { + dev_err(dev, "dma_map_single Tx failed\n"); + return -ENOMEM; + } + } + + if (xfer->rx_buf != NULL) { + xfer->rx_dma = dma_map_single(rx_dev, + xfer->rx_buf, xfer->len, + DMA_FROM_DEVICE); + if (dma_mapping_error(dev, xfer->rx_dma)) { + dev_err(dev, "dma_map_single Rx failed\n"); + dma_unmap_single(tx_dev, xfer->tx_dma, + xfer->len, DMA_TO_DEVICE); + return -ENOMEM; + } + } + } + + master->cur_msg_mapped = true; + + return 0; +} + +static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) +{ + struct spi_transfer *xfer; + struct device *tx_dev, *rx_dev; + + if (!master->cur_msg_mapped || msg->is_dma_mapped || !master->can_dma) + return 0; + + tx_dev = &master->dma_tx->dev->device; + rx_dev = &master->dma_rx->dev->device; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if (!master->can_dma(master, msg->spi, xfer)) + continue; + + if (xfer->rx_buf) + dma_unmap_single(rx_dev, xfer->rx_dma, xfer->len, + DMA_FROM_DEVICE); + if (xfer->tx_buf) + dma_unmap_single(tx_dev, xfer->tx_dma, xfer->len, + DMA_TO_DEVICE); + } + + return 0; +} + /* * spi_transfer_one_message - Default implementation of transfer_one_message() * @@ -752,6 +825,13 @@ static void spi_pump_messages(struct kthread_work *work) master->cur_msg_prepared = true; } + ret = spi_map_msg(master, master->cur_msg); + if (ret) { + master->cur_msg->status = ret; + spi_finalize_current_message(master); + return; + } + ret = master->transfer_one_message(master, master->cur_msg); if (ret) { dev_err(&master->dev, @@ -841,6 +921,8 @@ void spi_finalize_current_message(struct spi_master *master) queue_kthread_work(&master->kworker, &master->pump_messages); spin_unlock_irqrestore(&master->queue_lock, flags); + spi_unmap_msg(master, mesg); + if (master->cur_msg_prepared && master->unprepare_message) { ret = master->unprepare_message(master, mesg); if (ret) { diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index a1d4ca290862..b354dcbed55b 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -25,6 +25,8 @@ #include #include +struct dma_chan; + /* * INTERFACES between SPI master-side drivers and SPI infrastructure. * (There's no SPI slave support for Linux yet...) @@ -386,6 +388,17 @@ struct spi_master { /* called on release() to free memory provided by spi_master */ void (*cleanup)(struct spi_device *spi); + /* + * Used to enable core support for DMA handling, if can_dma() + * exists and returns true then the transfer will be mapped + * prior to transfer_one() being called. The driver should + * not modify or store xfer and dma_tx and dma_rx must be set + * while the device is prepared. + */ + bool (*can_dma)(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer); + /* * These hooks are for drivers that want to use the generic * master transfer queueing mechanism. If these are used, the @@ -404,6 +417,7 @@ struct spi_master { bool rt; bool auto_runtime_pm; bool cur_msg_prepared; + bool cur_msg_mapped; struct completion xfer_completion; int (*prepare_transfer_hardware)(struct spi_master *master); @@ -425,6 +439,10 @@ struct spi_master { /* gpio chip select */ int *cs_gpios; + + /* DMA channels for use with core dmaengine helpers */ + struct dma_chan *dma_tx; + struct dma_chan *dma_rx; }; static inline void *spi_master_get_devdata(struct spi_master *master) From 64b67defe4eb4de2d2df8acd5584a9e28fa727d3 Mon Sep 17 00:00:00 2001 From: "Shimoda, Yoshihiro" Date: Mon, 3 Feb 2014 10:43:46 +0900 Subject: [PATCH 025/201] spi: rspi: fix build error when CONFIG_OF is not set This patch fixes an issue that the following build error happens when the CONFIG_OF is not set: drivers/spi/spi-rspi.c: In function 'rspi_probe': drivers/spi/spi-rspi.c:1203:26: error: 'rspi_of_match' undeclared (first use in this function) Signed-off-by: Yoshihiro Shimoda Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 34ad4bca8a41..e5cfc3d77b8c 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -1164,6 +1164,7 @@ static int rspi_parse_dt(struct device *dev, struct spi_master *master) return 0; } #else +#define rspi_of_match NULL static inline int rspi_parse_dt(struct device *dev, struct spi_master *master) { return -EINVAL; From c7a26f121df611caa47576a169627bfd1c3d1b38 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 2 Feb 2014 10:59:48 +0400 Subject: [PATCH 026/201] spi: clps711x: Simplify handling of RX & TX buffers Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 374ba4a48a9e..89e5ea843fd0 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -32,7 +32,6 @@ struct spi_clps711x_data { u8 *tx_buf; u8 *rx_buf; - int count; int len; int chipselect[0]; @@ -93,11 +92,12 @@ static int spi_clps711x_transfer_one_message(struct spi_master *master, struct spi_clps711x_data *hw = spi_master_get_devdata(master); struct spi_transfer *xfer; int status = 0, cs = hw->chipselect[msg->spi->chip_select]; - u32 data; spi_clps711x_setup_mode(msg->spi); list_for_each_entry(xfer, &msg->transfers, transfer_list) { + u8 data; + if (spi_clps711x_setup_xfer(msg->spi, xfer)) { status = -EINVAL; goto out_xfr; @@ -107,13 +107,12 @@ static int spi_clps711x_transfer_one_message(struct spi_master *master, reinit_completion(&hw->done); - hw->count = 0; hw->len = xfer->len; hw->tx_buf = (u8 *)xfer->tx_buf; hw->rx_buf = (u8 *)xfer->rx_buf; /* Initiate transfer */ - data = hw->tx_buf ? hw->tx_buf[hw->count] : 0; + data = hw->tx_buf ? *hw->tx_buf++ : 0; clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO); wait_for_completion(&hw->done); @@ -138,18 +137,16 @@ out_xfr: static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) { struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id; - u32 data; + u8 data; /* Handle RX */ data = clps_readb(SYNCIO); if (hw->rx_buf) - hw->rx_buf[hw->count] = (u8)data; - - hw->count++; + *hw->rx_buf++ = data; /* Handle TX */ - if (hw->count < hw->len) { - data = hw->tx_buf ? hw->tx_buf[hw->count] : 0; + if (--hw->len > 0) { + data = hw->tx_buf ? *hw->tx_buf++ : 0; clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO); } else complete(&hw->done); From 8dda9d9a48baa4a4e0ff6ac9d8f1672f3bf6dfa5 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 2 Feb 2014 10:59:49 +0400 Subject: [PATCH 027/201] spi: clps711x: Add support for 1-8 BPW transfers This patch adds support for 1 to 8 BPW to driver and removes excess BPW validation since this is already checked by SPI core. Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 39 ++++++++++++++++---------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 89e5ea843fd0..89fef4712e9b 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -32,6 +32,7 @@ struct spi_clps711x_data { u8 *tx_buf; u8 *rx_buf; + unsigned int bpw; int len; int chipselect[0]; @@ -57,18 +58,12 @@ static void spi_clps711x_setup_mode(struct spi_device *spi) clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3); } -static int spi_clps711x_setup_xfer(struct spi_device *spi, - struct spi_transfer *xfer) +static void spi_clps711x_setup_xfer(struct spi_device *spi, + struct spi_transfer *xfer) { u32 speed = xfer->speed_hz ? : spi->max_speed_hz; - u8 bpw = xfer->bits_per_word; struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master); - if (bpw != 8) { - dev_err(&spi->dev, "Unsupported master bus width %i\n", bpw); - return -EINVAL; - } - /* Setup SPI frequency divider */ if (!speed || (speed >= hw->max_speed_hz)) clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | @@ -82,38 +77,36 @@ static int spi_clps711x_setup_xfer(struct spi_device *spi, else clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | SYSCON1_ADCKSEL(0), SYSCON1); - - return 0; } static int spi_clps711x_transfer_one_message(struct spi_master *master, struct spi_message *msg) { struct spi_clps711x_data *hw = spi_master_get_devdata(master); + struct spi_device *spi = msg->spi; struct spi_transfer *xfer; - int status = 0, cs = hw->chipselect[msg->spi->chip_select]; + int cs = hw->chipselect[spi->chip_select]; - spi_clps711x_setup_mode(msg->spi); + spi_clps711x_setup_mode(spi); list_for_each_entry(xfer, &msg->transfers, transfer_list) { u8 data; - if (spi_clps711x_setup_xfer(msg->spi, xfer)) { - status = -EINVAL; - goto out_xfr; - } + spi_clps711x_setup_xfer(spi, xfer); - gpio_set_value(cs, !!(msg->spi->mode & SPI_CS_HIGH)); + gpio_set_value(cs, !!(spi->mode & SPI_CS_HIGH)); reinit_completion(&hw->done); hw->len = xfer->len; + hw->bpw = xfer->bits_per_word ? : spi->bits_per_word; hw->tx_buf = (u8 *)xfer->tx_buf; hw->rx_buf = (u8 *)xfer->rx_buf; /* Initiate transfer */ data = hw->tx_buf ? *hw->tx_buf++ : 0; - clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO); + clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, + SYNCIO); wait_for_completion(&hw->done); @@ -122,13 +115,12 @@ static int spi_clps711x_transfer_one_message(struct spi_master *master, if (xfer->cs_change || list_is_last(&xfer->transfer_list, &msg->transfers)) - gpio_set_value(cs, !(msg->spi->mode & SPI_CS_HIGH)); + gpio_set_value(cs, !(spi->mode & SPI_CS_HIGH)); msg->actual_length += xfer->len; } -out_xfr: - msg->status = status; + msg->status = 0; spi_finalize_current_message(master); return 0; @@ -147,7 +139,8 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) /* Handle TX */ if (--hw->len > 0) { data = hw->tx_buf ? *hw->tx_buf++ : 0; - clps_writel(data | SYNCIO_FRMLEN(8) | SYNCIO_TXFRMEN, SYNCIO); + clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, + SYNCIO); } else complete(&hw->done); @@ -181,7 +174,7 @@ static int spi_clps711x_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->mode_bits = SPI_CPHA | SPI_CS_HIGH; - master->bits_per_word_mask = SPI_BPW_MASK(8); + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8); master->num_chipselect = pdata->num_chipselect; master->setup = spi_clps711x_setup; master->transfer_one_message = spi_clps711x_transfer_one_message; From 3e9ea4b4d51d6fce449427bb411debaa4d52397d Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sun, 2 Feb 2014 10:59:50 +0400 Subject: [PATCH 028/201] spi: clps711x: Use SPI-core "cs_gpios" property for storing GPIOs Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index 89fef4712e9b..df086ee4cdaa 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -34,17 +34,12 @@ struct spi_clps711x_data { u8 *rx_buf; unsigned int bpw; int len; - - int chipselect[0]; }; static int spi_clps711x_setup(struct spi_device *spi) { - struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master); - /* We are expect that SPI-device is not selected */ - gpio_direction_output(hw->chipselect[spi->chip_select], - !(spi->mode & SPI_CS_HIGH)); + gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); return 0; } @@ -85,7 +80,6 @@ static int spi_clps711x_transfer_one_message(struct spi_master *master, struct spi_clps711x_data *hw = spi_master_get_devdata(master); struct spi_device *spi = msg->spi; struct spi_transfer *xfer; - int cs = hw->chipselect[spi->chip_select]; spi_clps711x_setup_mode(spi); @@ -94,7 +88,7 @@ static int spi_clps711x_transfer_one_message(struct spi_master *master, spi_clps711x_setup_xfer(spi, xfer); - gpio_set_value(cs, !!(spi->mode & SPI_CS_HIGH)); + gpio_set_value(spi->cs_gpio, !!(spi->mode & SPI_CS_HIGH)); reinit_completion(&hw->done); @@ -115,7 +109,7 @@ static int spi_clps711x_transfer_one_message(struct spi_master *master, if (xfer->cs_change || list_is_last(&xfer->transfer_list, &msg->transfers)) - gpio_set_value(cs, !(spi->mode & SPI_CS_HIGH)); + gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); msg->actual_length += xfer->len; } @@ -164,12 +158,15 @@ static int spi_clps711x_probe(struct platform_device *pdev) return -EINVAL; } - master = spi_alloc_master(&pdev->dev, - sizeof(struct spi_clps711x_data) + - sizeof(int) * pdata->num_chipselect); - if (!master) { - dev_err(&pdev->dev, "SPI allocating memory error\n"); + master = spi_alloc_master(&pdev->dev, sizeof(*hw)); + if (!master) return -ENOMEM; + + master->cs_gpios = devm_kzalloc(&pdev->dev, sizeof(int) * + pdata->num_chipselect, GFP_KERNEL); + if (!master->cs_gpios) { + ret = -ENOMEM; + goto err_out; } master->bus_num = pdev->id; @@ -182,13 +179,13 @@ static int spi_clps711x_probe(struct platform_device *pdev) hw = spi_master_get_devdata(master); for (i = 0; i < master->num_chipselect; i++) { - hw->chipselect[i] = pdata->chipselect[i]; - if (!gpio_is_valid(hw->chipselect[i])) { + master->cs_gpios[i] = pdata->chipselect[i]; + if (!gpio_is_valid(master->cs_gpios[i])) { dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i); ret = -EINVAL; goto err_out; } - if (devm_gpio_request(&pdev->dev, hw->chipselect[i], NULL)) { + if (devm_gpio_request(&pdev->dev, master->cs_gpios[i], NULL)) { dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i); ret = -EINVAL; goto err_out; From 2bd16e3e23d9df41592c6b257c59b6860a9cc3ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Sun, 2 Feb 2014 16:24:12 +0100 Subject: [PATCH 029/201] spi: omap2-mcspi: Do not configure the controller on each transfer unless needed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit spi_transfer->speed_hz and spi_transfer->bits_per_word used to only be set when not using the default settings but are not set on every transfer, causing omap2_mcspi_setup_transfer to be called on each transfer. This patch changes the check to only call omap2_mcspi_setup_transfer if the settings needs to be changed. Signed-off-by: Stefan Sørensen Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index a72127f08e39..965539b0dbfb 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1057,12 +1057,15 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) status = -EINVAL; break; } - if (par_override || t->speed_hz || t->bits_per_word) { + if (par_override || + (t->speed_hz != spi->max_speed_hz) || + (t->bits_per_word != spi->bits_per_word)) { par_override = 1; status = omap2_mcspi_setup_transfer(spi, t); if (status < 0) break; - if (!t->speed_hz && !t->bits_per_word) + if (t->speed_hz == spi->max_speed_hz && + t->bits_per_word == spi->bits_per_word) par_override = 0; } if (cd && cd->cs_per_word) { From faee9b05f69f22e4d65fb2c24f82eea9c6fe4062 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20S=C3=B8rensen?= Date: Sun, 2 Feb 2014 16:24:25 +0100 Subject: [PATCH 030/201] spi: omap2-mcspi: Support divide-by-n clock dividers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently a divide-by-2^n clock is used, causing a very coarse clock selection, i.e. a 10MHz device will need to use a 6MHz clock. The McSPI can also use a divide-by-n clock, this patch adds support for selecting that when possible. Signed-off-by: Stefan Sørensen Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 43 +++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 965539b0dbfb..8f0afdb067b8 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -45,6 +45,7 @@ #include #define OMAP2_MCSPI_MAX_FREQ 48000000 +#define OMAP2_MCSPI_MAX_DIVIDER 4096 #define OMAP2_MCSPI_MAX_FIFODEPTH 64 #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF #define SPI_AUTOSUSPEND_TIMEOUT 2000 @@ -89,6 +90,7 @@ #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) #define OMAP2_MCSPI_CHCONF_FFET BIT(27) #define OMAP2_MCSPI_CHCONF_FFER BIT(28) +#define OMAP2_MCSPI_CHCONF_CLKG BIT(29) #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) @@ -96,6 +98,7 @@ #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) #define OMAP2_MCSPI_CHCTRL_EN BIT(0) +#define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8) #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) @@ -149,7 +152,7 @@ struct omap2_mcspi_cs { int word_len; struct list_head node; /* Context save and restore shadow register */ - u32 chconf0; + u32 chconf0, chctrl0; }; static inline void mcspi_write_reg(struct spi_master *master, @@ -230,10 +233,16 @@ static void omap2_mcspi_set_dma_req(const struct spi_device *spi, static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) { + struct omap2_mcspi_cs *cs = spi->controller_state; u32 l; - l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0; - mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l); + l = cs->chctrl0; + if (enable) + l |= OMAP2_MCSPI_CHCTRL_EN; + else + l &= ~OMAP2_MCSPI_CHCTRL_EN; + cs->chctrl0 = l; + mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); /* Flash post-writes */ mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); } @@ -840,7 +849,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi *mcspi; struct spi_master *spi_cntrl; - u32 l = 0, div = 0; + u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0; u8 word_len = spi->bits_per_word; u32 speed_hz = spi->max_speed_hz; @@ -856,7 +865,17 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, speed_hz = t->speed_hz; speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ); - div = omap2_mcspi_calc_divisor(speed_hz); + if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) { + clkd = omap2_mcspi_calc_divisor(speed_hz); + speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd; + clkg = 0; + } else { + div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz; + speed_hz = OMAP2_MCSPI_MAX_FREQ / div; + clkd = (div - 1) & 0xf; + extclk = (div - 1) >> 4; + clkg = OMAP2_MCSPI_CHCONF_CLKG; + } l = mcspi_cached_chconf0(spi); @@ -885,7 +904,16 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, /* set clock divisor */ l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK; - l |= div << 2; + l |= clkd << 2; + + /* set clock granularity */ + l &= ~OMAP2_MCSPI_CHCONF_CLKG; + l |= clkg; + if (clkg) { + cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK; + cs->chctrl0 |= extclk << 8; + mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); + } /* set SPI mode 0..3 */ if (spi->mode & SPI_CPOL) @@ -900,7 +928,7 @@ static int omap2_mcspi_setup_transfer(struct spi_device *spi, mcspi_write_chconf0(spi, l); dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", - OMAP2_MCSPI_MAX_FREQ >> div, + speed_hz, (spi->mode & SPI_CPHA) ? "trailing" : "leading", (spi->mode & SPI_CPOL) ? "inverted" : "normal"); @@ -972,6 +1000,7 @@ static int omap2_mcspi_setup(struct spi_device *spi) cs->base = mcspi->base + spi->chip_select * 0x14; cs->phys = mcspi->phys + spi->chip_select * 0x14; cs->chconf0 = 0; + cs->chctrl0 = 0; spi->controller_state = cs; /* Link this to context save list */ list_add_tail(&cs->node, &ctx->cs); From 5dd1ad23af689591d70be06ee6efcc57d1ec2d16 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Feb 2014 11:06:24 +0100 Subject: [PATCH 031/201] spi: rspi: Only enable interrupts when there's a need to wait rspi_wait_for_interrupt() unconditionally enables interrupts, even when the wait condition is already satisfied. This causes a high interrupt load (2 interrupts/byte for full-duplex Single SPI transfers, 1 interrupt/byte for RSPI with TX Only mode, or QSPI in unidirectional Dual or Quad Transfer mode). Change this to return immediately when the wait condition is satisfied. This dramatically reduces the interrupt load, especially in high-speed Quad Transfer mode, and increases transfer speed, as no interrupts need to be handled when there's space available in the output FIFO, or data available in the input FIFO. Benchmark results for QSPI on r8a7791 while reading 1 MiB from 30 MHz SPI FLASH on the Koelsch development board: Before: Single SPI Dual SPI Quad SPI Interrupts: 2096856 1048592 1048594 Mbps: 0.9 1.6 1.6 After: Single SPI Dual SPI Quad SPI Interrupts: 1048569 21295 8 Mbps: 0.7 10.8 12.9 I don't know why Single SPI slowed down a bit. I've also verified functionality for RSPI-RZ on r7s72100, but don't have benchmark results as there's no SPI FLASH connected to RSPI on the Genmai development board. Unlike RSPI and QSPI, RSPI-RZ has separate interrupts for RX and TX, which shows that Single SPI transfers now generate (mostly) RX interrupts, as expected. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index e5cfc3d77b8c..04528888a53f 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -391,6 +391,9 @@ static int rspi_wait_for_interrupt(struct rspi_data *rspi, u8 wait_mask, int ret; rspi->spsr = rspi_read8(rspi, RSPI_SPSR); + if (rspi->spsr & wait_mask) + return 0; + rspi_enable_irq(rspi, enable_bit); ret = wait_event_timeout(rspi->wait, rspi->spsr & wait_mask, HZ); if (ret == 0 && !(rspi->spsr & wait_mask)) From e1bde3b11fedace5042f0232339da90bc85666af Mon Sep 17 00:00:00 2001 From: SeongJae Park Date: Tue, 4 Feb 2014 15:58:09 +0900 Subject: [PATCH 032/201] spi: fix pointer-integer size mismatch warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the pointer-integer size mismatch warning below: drivers/spi/spi-gpio.c: In function ‘spi_gpio_setup’: drivers/spi/spi-gpio.c:252:8: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] cs = (unsigned int) spi->controller_data; ^ Signed-off-by: SeongJae Park Signed-off-by: Mark Brown --- drivers/spi/spi-gpio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 7beeb29472ac..dd4fe5036220 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -250,7 +250,7 @@ static int spi_gpio_setup(struct spi_device *spi) /* * ... otherwise, take it from spi->controller_data */ - cs = (unsigned int) spi->controller_data; + cs = (unsigned int)(uintptr_t) spi->controller_data; } if (!spi->controller_state) { From 4302a59629f7a0bd70fd1605d2b558597517372a Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Fri, 31 Jan 2014 13:44:59 +0100 Subject: [PATCH 033/201] spi: fsl: Fix problem with multi message transfers When used via spidev with more than one messages to tranfer via SPI_IOC_MESSAGE the current implementation would return with -EINVAL, since bits_per_word and speed_hz are set in all transfer structs. And in the 2nd loop status will stay at -EINVAL as its not overwritten again via fsl_spi_setup_transfer(). This patch changes this behavious by first checking if one of the messages uses different settings. If this is the case the function will return with -EINVAL. If not, the messages are transferred correctly. Signed-off-by: Stefan Roese Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 119f7af94537..4dcb2929c01f 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -362,18 +362,28 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t, static void fsl_spi_do_one_msg(struct spi_message *m) { struct spi_device *spi = m->spi; - struct spi_transfer *t; + struct spi_transfer *t, *first; unsigned int cs_change; const int nsecs = 50; int status; + /* Don't allow changes if CS is active */ + first = list_first_entry(&m->transfers, struct spi_transfer, + transfer_list); + list_for_each_entry(t, &m->transfers, transfer_list) { + if ((first->bits_per_word != t->bits_per_word) || + (first->speed_hz != t->speed_hz)) { + status = -EINVAL; + dev_err(&spi->dev, + "bits_per_word/speed_hz should be same for the same SPI transfer\n"); + return; + } + } + cs_change = 1; - status = 0; + status = -EINVAL; list_for_each_entry(t, &m->transfers, transfer_list) { if (t->bits_per_word || t->speed_hz) { - /* Don't allow changes if CS is active */ - status = -EINVAL; - if (cs_change) status = fsl_spi_setup_transfer(spi, t); if (status < 0) From 4ddc86005b1266b81c7b1b574a2402d3d8deda44 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 24 Jan 2014 19:00:55 +0000 Subject: [PATCH 034/201] spi/s3c64xx: Remove unused /CS GPIO management The GPIO enable and disable is done in the core so does not need to be replicated in the driver, delete the unneeded code. enable_cs() was not referenced at all. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index ae907dde1371..da32cd9c9b59 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -555,23 +555,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(chcfg, regs + S3C64XX_SPI_CH_CFG); } -static inline void enable_cs(struct s3c64xx_spi_driver_data *sdd, - struct spi_device *spi) -{ - if (sdd->tgl_spi != NULL) { /* If last device toggled after mssg */ - if (sdd->tgl_spi != spi) { /* if last mssg on diff device */ - /* Deselect the last toggled device */ - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, - spi->mode & SPI_CS_HIGH ? 0 : 1); - } - sdd->tgl_spi = NULL; - } - - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 1 : 0); -} - static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, int timeout_ms) { @@ -691,16 +674,6 @@ static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, return 0; } -static inline void disable_cs(struct s3c64xx_spi_driver_data *sdd, - struct spi_device *spi) -{ - if (sdd->tgl_spi == spi) - sdd->tgl_spi = NULL; - - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, spi->mode & SPI_CS_HIGH ? 0 : 1); -} - static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) { void __iomem *regs = sdd->regs; @@ -1092,14 +1065,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi) pm_runtime_put(&sdd->pdev->dev); writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - disable_cs(sdd, spi); return 0; setup_exit: pm_runtime_put(&sdd->pdev->dev); /* setup() returns with device de-selected */ writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL); - disable_cs(sdd, spi); gpio_free(cs->line); spi_set_ctldata(spi, NULL); From 3700c6eb1e41a898c35c8dd4d5b10dc65fdaf486 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 24 Jan 2014 20:05:43 +0000 Subject: [PATCH 035/201] spi/s3c64xx: Split wait_for_xfer() into PIO and DMA versions There is no meaningful code sharing between the PIO and DMA variants (just the timeout calculation) so in order to make the code easier to work with split the two cases. Looking at the code it is not clear how the PIO version works for large transmits, greater than FIFO size is only handled for RX. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 172 ++++++++++++++++++++------------------ 1 file changed, 92 insertions(+), 80 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index da32cd9c9b59..e515b8a6f590 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -576,100 +576,109 @@ static u32 s3c64xx_spi_wait_for_timeout(struct s3c64xx_spi_driver_data *sdd, return RX_FIFO_LVL(status, sdd); } -static int wait_for_xfer(struct s3c64xx_spi_driver_data *sdd, - struct spi_transfer *xfer, int dma_mode) +static int wait_for_dma(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) { void __iomem *regs = sdd->regs; unsigned long val; + u32 status; int ms; /* millisecs to xfer 'len' bytes @ 'cur_speed' */ ms = xfer->len * 8 * 1000 / sdd->cur_speed; ms += 10; /* some tolerance */ - if (dma_mode) { - val = msecs_to_jiffies(ms) + 10; - val = wait_for_completion_timeout(&sdd->xfer_completion, val); - } else { - u32 status; - val = msecs_to_loops(ms); - do { + val = msecs_to_jiffies(ms) + 10; + val = wait_for_completion_timeout(&sdd->xfer_completion, val); + + /* + * If the previous xfer was completed within timeout, then + * proceed further else return -EIO. + * DmaTx returns after simply writing data in the FIFO, + * w/o waiting for real transmission on the bus to finish. + * DmaRx returns only after Dma read data from FIFO which + * needs bus transmission to finish, so we don't worry if + * Xfer involved Rx(with or without Tx). + */ + if (val && !xfer->rx_buf) { + val = msecs_to_loops(10); + status = readl(regs + S3C64XX_SPI_STATUS); + while ((TX_FIFO_LVL(status, sdd) + || !S3C64XX_SPI_ST_TX_DONE(status, sdd)) + && --val) { + cpu_relax(); status = readl(regs + S3C64XX_SPI_STATUS); - } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); - } - - if (dma_mode) { - u32 status; - - /* - * If the previous xfer was completed within timeout, then - * proceed further else return -EIO. - * DmaTx returns after simply writing data in the FIFO, - * w/o waiting for real transmission on the bus to finish. - * DmaRx returns only after Dma read data from FIFO which - * needs bus transmission to finish, so we don't worry if - * Xfer involved Rx(with or without Tx). - */ - if (val && !xfer->rx_buf) { - val = msecs_to_loops(10); - status = readl(regs + S3C64XX_SPI_STATUS); - while ((TX_FIFO_LVL(status, sdd) - || !S3C64XX_SPI_ST_TX_DONE(status, sdd)) - && --val) { - cpu_relax(); - status = readl(regs + S3C64XX_SPI_STATUS); - } - } - /* If timed out while checking rx/tx status return error */ - if (!val) - return -EIO; - } else { - int loops; - u32 cpy_len; - u8 *buf; + } - /* If it was only Tx */ - if (!xfer->rx_buf) { - sdd->state &= ~TXBUSY; - return 0; + /* If timed out while checking rx/tx status return error */ + if (!val) + return -EIO; + + return 0; +} + +static int wait_for_pio(struct s3c64xx_spi_driver_data *sdd, + struct spi_transfer *xfer) +{ + void __iomem *regs = sdd->regs; + unsigned long val; + u32 status; + int loops; + u32 cpy_len; + u8 *buf; + int ms; + + /* millisecs to xfer 'len' bytes @ 'cur_speed' */ + ms = xfer->len * 8 * 1000 / sdd->cur_speed; + ms += 10; /* some tolerance */ + + val = msecs_to_loops(ms); + do { + status = readl(regs + S3C64XX_SPI_STATUS); + } while (RX_FIFO_LVL(status, sdd) < xfer->len && --val); + + + /* If it was only Tx */ + if (!xfer->rx_buf) { + sdd->state &= ~TXBUSY; + return 0; + } + + /* + * If the receive length is bigger than the controller fifo + * size, calculate the loops and read the fifo as many times. + * loops = length / max fifo size (calculated by using the + * fifo mask). + * For any size less than the fifo size the below code is + * executed atleast once. + */ + loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1); + buf = xfer->rx_buf; + do { + /* wait for data to be received in the fifo */ + cpy_len = s3c64xx_spi_wait_for_timeout(sdd, + (loops ? ms : 0)); + + switch (sdd->cur_bpw) { + case 32: + ioread32_rep(regs + S3C64XX_SPI_RX_DATA, + buf, cpy_len / 4); + break; + case 16: + ioread16_rep(regs + S3C64XX_SPI_RX_DATA, + buf, cpy_len / 2); + break; + default: + ioread8_rep(regs + S3C64XX_SPI_RX_DATA, + buf, cpy_len); + break; } - /* - * If the receive length is bigger than the controller fifo - * size, calculate the loops and read the fifo as many times. - * loops = length / max fifo size (calculated by using the - * fifo mask). - * For any size less than the fifo size the below code is - * executed atleast once. - */ - loops = xfer->len / ((FIFO_LVL_MASK(sdd) >> 1) + 1); - buf = xfer->rx_buf; - do { - /* wait for data to be received in the fifo */ - cpy_len = s3c64xx_spi_wait_for_timeout(sdd, - (loops ? ms : 0)); - - switch (sdd->cur_bpw) { - case 32: - ioread32_rep(regs + S3C64XX_SPI_RX_DATA, - buf, cpy_len / 4); - break; - case 16: - ioread16_rep(regs + S3C64XX_SPI_RX_DATA, - buf, cpy_len / 2); - break; - default: - ioread8_rep(regs + S3C64XX_SPI_RX_DATA, - buf, cpy_len); - break; - } - - buf = buf + cpy_len; - } while (loops--); - sdd->state &= ~RXBUSY; - } + buf = buf + cpy_len; + } while (loops--); + sdd->state &= ~RXBUSY; return 0; } @@ -902,7 +911,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, spin_unlock_irqrestore(&sdd->lock, flags); - status = wait_for_xfer(sdd, xfer, use_dma); + if (use_dma) + status = wait_for_dma(sdd, xfer); + else + status = wait_for_pio(sdd, xfer); if (status) { dev_err(&spi->dev, "I/O Error: rx-%d tx-%d res:rx-%c tx-%c len-%d\n", From 6cac167b826eced25a2756b996a93c6f7833c49b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 4 Feb 2014 16:58:50 +0100 Subject: [PATCH 036/201] spi: pl022: Simplify clock handling Make use of clk_prepare_enable and clk_disable_unprepare to simplify code. No functional change. Signed-off-by: Ulf Hansson Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 4ec49eae6141..5f7594bc2086 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2183,13 +2183,7 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) goto err_no_clk; } - status = clk_prepare(pl022->clk); - if (status) { - dev_err(&adev->dev, "could not prepare SSP/SPI bus clock\n"); - goto err_clk_prep; - } - - status = clk_enable(pl022->clk); + status = clk_prepare_enable(pl022->clk); if (status) { dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); goto err_no_clk_en; @@ -2250,10 +2244,8 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) if (platform_info->enable_dma) pl022_dma_remove(pl022); err_no_irq: - clk_disable(pl022->clk); + clk_disable_unprepare(pl022->clk); err_no_clk_en: - clk_unprepare(pl022->clk); - err_clk_prep: err_no_clk: err_no_ioremap: amba_release_regions(adev); @@ -2281,8 +2273,7 @@ pl022_remove(struct amba_device *adev) if (pl022->master_info->enable_dma) pl022_dma_remove(pl022); - clk_disable(pl022->clk); - clk_unprepare(pl022->clk); + clk_disable_unprepare(pl022->clk); amba_release_regions(adev); tasklet_disable(&pl022->pump_transfers); return 0; From 8535736c27cc4e25b9948d857138315f45b6fa34 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Tue, 4 Feb 2014 16:58:51 +0100 Subject: [PATCH 037/201] spi: pl022: Remove redundant pinctrl to default state in probe The driver core is now taking care of putting our pins into default state at probe. Thus we can remove the redundant call for it in probe. Signed-off-by: Ulf Hansson Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 5f7594bc2086..74a072924b65 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2109,8 +2109,6 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id) pl022->chipselects = devm_kzalloc(dev, num_cs * sizeof(int), GFP_KERNEL); - pinctrl_pm_select_default_state(dev); - /* * Bus Number Which has been Assigned to this SSP controller * on this board From 3a2eba9bd0a6447dfbc01635e4cd0689f5f2bdad Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Jan 2014 20:17:03 +0000 Subject: [PATCH 038/201] spi: Provide core support for full duplex devices It is fairly common for SPI devices to require that one or both transfer directions is always active. Currently drivers open code this in various ways with varying degrees of efficiency. Start factoring this out by providing flags SPI_MASTER_MUST_TX and SPI_MASTER_MUST_RX. These will cause the core to provide buffers for the requested direction if none are specified in the underlying transfer. Currently this is fairly inefficient since we actually allocate a data buffer which may get large, support for mapping transfers using a scatterlist will allow us to avoid this for DMA based transfers. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 47 +++++++++++++++++++++++++++++++++++++++++ include/linux/spi/spi.h | 6 ++++++ 2 files changed, 53 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index bcdaa74f1c8e..bb7cf561c311 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -587,6 +587,49 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg) struct device *dev = master->dev.parent; struct device *tx_dev, *rx_dev; struct spi_transfer *xfer; + void *tmp; + size_t max_tx, max_rx; + + if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { + max_tx = 0; + max_rx = 0; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + if ((master->flags & SPI_MASTER_MUST_TX) && + !xfer->tx_buf) + max_tx = max(xfer->len, max_tx); + if ((master->flags & SPI_MASTER_MUST_RX) && + !xfer->rx_buf) + max_rx = max(xfer->len, max_rx); + } + + if (max_tx) { + tmp = krealloc(master->dummy_tx, max_tx, + GFP_KERNEL | GFP_DMA); + if (!tmp) + return -ENOMEM; + master->dummy_tx = tmp; + memset(tmp, 0, max_tx); + } + + if (max_rx) { + tmp = krealloc(master->dummy_rx, max_rx, + GFP_KERNEL | GFP_DMA); + if (!tmp) + return -ENOMEM; + master->dummy_rx = tmp; + } + + if (max_tx || max_rx) { + list_for_each_entry(xfer, &msg->transfers, + transfer_list) { + if (!xfer->tx_buf) + xfer->tx_buf = master->dummy_tx; + if (!xfer->rx_buf) + xfer->rx_buf = master->dummy_rx; + } + } + } if (msg->is_dma_mapped || !master->can_dma) return 0; @@ -759,6 +802,10 @@ static void spi_pump_messages(struct kthread_work *work) } master->busy = false; spin_unlock_irqrestore(&master->queue_lock, flags); + kfree(master->dummy_rx); + master->dummy_rx = NULL; + kfree(master->dummy_tx); + master->dummy_tx = NULL; if (master->unprepare_transfer_hardware && master->unprepare_transfer_hardware(master)) dev_err(&master->dev, diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index b354dcbed55b..31a5b0ee93ec 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -347,6 +347,8 @@ struct spi_master { #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ +#define SPI_MASTER_MUST_RX BIT(3) /* requires rx */ +#define SPI_MASTER_MUST_TX BIT(4) /* requires tx */ /* lock and mutex for SPI bus locking */ spinlock_t bus_lock_spinlock; @@ -443,6 +445,10 @@ struct spi_master { /* DMA channels for use with core dmaengine helpers */ struct dma_chan *dma_tx; struct dma_chan *dma_rx; + + /* dummy data for full duplex devices */ + void *dummy_rx; + void *dummy_tx; }; static inline void *spi_master_get_devdata(struct spi_master *master) From 6ad45a27cbe343ec8d7888e5edf6335499a4b555 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sun, 2 Feb 2014 13:47:47 +0000 Subject: [PATCH 039/201] spi: Make core DMA mapping functions generate scatterlists We cannot unconditionally use dma_map_single() to map data for use with SPI since transfers may exceed a page and virtual addresses may not be provided with physically contiguous pages. Further, addresses allocated using vmalloc() need to be mapped differently to other addresses. Currently only the MXS driver handles all this, a few drivers do handle the possibility that buffers may not be physically contiguous which is the main potential problem but many don't even do that. Factoring this out into the core will make it easier for drivers to do a good job so if the driver is using the core DMA code then generate a scatterlist instead of mapping to a single address so do that. This code is mainly based on a combination of the existing code in the MXS and PXA2xx drivers. In future we should be able to extend it to allow the core to concatenate adjacent transfers if they are compatible, improving performance. Currently for simplicity clients are not allowed to use the scatterlist when they do DMA mapping, in the future the existing single address mappings will be replaced with use of the scatterlist most likely as part of pre-verifying transfers. This change makes it mandatory to use scatterlists when using the core DMA mapping so update the s3c64xx driver to do this when used with dmaengine. Doing so makes the code more ugly but it is expected that the old s3c-dma code can be removed very soon. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 14 ++++-- drivers/spi/spi.c | 101 ++++++++++++++++++++++++++++---------- include/linux/spi/spi.h | 7 +++ 3 files changed, 94 insertions(+), 28 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index e515b8a6f590..25c9bd409a87 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -381,7 +381,7 @@ static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, #else static void prepare_dma(struct s3c64xx_spi_dma_data *dma, - unsigned len, dma_addr_t buf) + struct sg_table *sgt) { struct s3c64xx_spi_driver_data *sdd; struct dma_slave_config config; @@ -407,8 +407,8 @@ static void prepare_dma(struct s3c64xx_spi_dma_data *dma, dmaengine_slave_config(dma->ch, &config); } - desc = dmaengine_prep_slave_single(dma->ch, buf, len, - dma->direction, DMA_PREP_INTERRUPT); + desc = dmaengine_prep_slave_sg(dma->ch, sgt->sgl, sgt->nents, + dma->direction, DMA_PREP_INTERRUPT); desc->callback = s3c64xx_spi_dmacb; desc->callback_param = dma; @@ -515,7 +515,11 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; +#ifndef CONFIG_S3C_DMA + prepare_dma(&sdd->tx_dma, &xfer->tx_sg); +#else prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); +#endif } else { switch (sdd->cur_bpw) { case 32: @@ -547,7 +551,11 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); +#ifndef CONFIG_S3C_DMA + prepare_dma(&sdd->rx_dma, &xfer->rx_sg); +#else prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); +#endif } } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index bb7cf561c311..49313dd0a144 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -582,13 +582,70 @@ static void spi_set_cs(struct spi_device *spi, bool enable) spi->master->set_cs(spi, !enable); } +static int spi_map_buf(struct spi_master *master, struct device *dev, + struct sg_table *sgt, void *buf, size_t len, + enum dma_data_direction dir) +{ + const bool vmalloced_buf = is_vmalloc_addr(buf); + const int desc_len = vmalloced_buf ? PAGE_SIZE : master->max_dma_len; + const int sgs = DIV_ROUND_UP(len, desc_len); + struct page *vm_page; + void *sg_buf; + size_t min; + int i, ret; + + ret = sg_alloc_table(sgt, sgs, GFP_KERNEL); + if (ret != 0) + return ret; + + for (i = 0; i < sgs; i++) { + min = min_t(size_t, len, desc_len); + + if (vmalloced_buf) { + vm_page = vmalloc_to_page(buf); + if (!vm_page) { + sg_free_table(sgt); + return -ENOMEM; + } + sg_buf = page_address(vm_page) + + ((size_t)buf & ~PAGE_MASK); + } else { + sg_buf = buf; + } + + sg_set_buf(&sgt->sgl[i], sg_buf, min); + + buf += min; + len -= min; + } + + ret = dma_map_sg(dev, sgt->sgl, sgt->nents, dir); + if (ret < 0) { + sg_free_table(sgt); + return ret; + } + + sgt->nents = ret; + + return 0; +} + +static void spi_unmap_buf(struct spi_master *master, struct device *dev, + struct sg_table *sgt, enum dma_data_direction dir) +{ + if (sgt->orig_nents) { + dma_unmap_sg(dev, sgt->sgl, sgt->orig_nents, dir); + sg_free_table(sgt); + } +} + static int spi_map_msg(struct spi_master *master, struct spi_message *msg) { - struct device *dev = master->dev.parent; struct device *tx_dev, *rx_dev; struct spi_transfer *xfer; void *tmp; size_t max_tx, max_rx; + int ret; if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { max_tx = 0; @@ -631,7 +688,7 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg) } } - if (msg->is_dma_mapped || !master->can_dma) + if (!master->can_dma) return 0; tx_dev = &master->dma_tx->dev->device; @@ -642,25 +699,21 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg) continue; if (xfer->tx_buf != NULL) { - xfer->tx_dma = dma_map_single(tx_dev, - (void *)xfer->tx_buf, - xfer->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, xfer->tx_dma)) { - dev_err(dev, "dma_map_single Tx failed\n"); - return -ENOMEM; - } + ret = spi_map_buf(master, tx_dev, &xfer->tx_sg, + (void *)xfer->tx_buf, xfer->len, + DMA_TO_DEVICE); + if (ret != 0) + return ret; } if (xfer->rx_buf != NULL) { - xfer->rx_dma = dma_map_single(rx_dev, - xfer->rx_buf, xfer->len, - DMA_FROM_DEVICE); - if (dma_mapping_error(dev, xfer->rx_dma)) { - dev_err(dev, "dma_map_single Rx failed\n"); - dma_unmap_single(tx_dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - return -ENOMEM; + ret = spi_map_buf(master, rx_dev, &xfer->rx_sg, + xfer->rx_buf, xfer->len, + DMA_FROM_DEVICE); + if (ret != 0) { + spi_unmap_buf(master, tx_dev, &xfer->tx_sg, + DMA_TO_DEVICE); + return ret; } } } @@ -675,7 +728,7 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) struct spi_transfer *xfer; struct device *tx_dev, *rx_dev; - if (!master->cur_msg_mapped || msg->is_dma_mapped || !master->can_dma) + if (!master->cur_msg_mapped || !master->can_dma) return 0; tx_dev = &master->dma_tx->dev->device; @@ -685,12 +738,8 @@ static int spi_unmap_msg(struct spi_master *master, struct spi_message *msg) if (!master->can_dma(master, msg->spi, xfer)) continue; - if (xfer->rx_buf) - dma_unmap_single(rx_dev, xfer->rx_dma, xfer->len, - DMA_FROM_DEVICE); - if (xfer->tx_buf) - dma_unmap_single(tx_dev, xfer->tx_dma, xfer->len, - DMA_TO_DEVICE); + spi_unmap_buf(master, rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE); + spi_unmap_buf(master, tx_dev, &xfer->tx_sg, DMA_TO_DEVICE); } return 0; @@ -1503,6 +1552,8 @@ int spi_register_master(struct spi_master *master) mutex_init(&master->bus_lock_mutex); master->bus_lock_flag = 0; init_completion(&master->xfer_completion); + if (!master->max_dma_len) + master->max_dma_len = INT_MAX; /* register the device, then userspace will see it. * registration fails if the bus ID is in use. diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 31a5b0ee93ec..0c23c835d48b 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -24,6 +24,7 @@ #include #include #include +#include struct dma_chan; @@ -268,6 +269,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * @auto_runtime_pm: the core should ensure a runtime PM reference is held * while the hardware is prepared, using the parent * device for the spidev + * @max_dma_len: Maximum length of a DMA transfer for the device. * @prepare_transfer_hardware: a message will soon arrive from the queue * so the subsystem requests the driver to prepare the transfer hardware * by issuing this call @@ -421,6 +423,7 @@ struct spi_master { bool cur_msg_prepared; bool cur_msg_mapped; struct completion xfer_completion; + size_t max_dma_len; int (*prepare_transfer_hardware)(struct spi_master *master); int (*transfer_one_message)(struct spi_master *master, @@ -533,6 +536,8 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); * (optionally) changing the chipselect status, then starting * the next transfer or completing this @spi_message. * @transfer_list: transfers are sequenced through @spi_message.transfers + * @tx_sg: Scatterlist for transmit, currently not for client use + * @rx_sg: Scatterlist for receive, currently not for client use * * SPI transfers always write the same number of bytes as they read. * Protocol drivers should always provide @rx_buf and/or @tx_buf. @@ -600,6 +605,8 @@ struct spi_transfer { dma_addr_t tx_dma; dma_addr_t rx_dma; + struct sg_table tx_sg; + struct sg_table rx_sg; unsigned cs_change:1; unsigned tx_nbits:3; From 3558fe900e8af6c3bfadeff24a12ffb19ac9b108 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 5 Feb 2014 14:05:05 +0100 Subject: [PATCH 040/201] spi: sunxi: Add Allwinner A31 SPI controller driver The Allwinner A31 has a new SPI controller IP compared to the older Allwinner SoCs. It supports DMA, but the driver only does PIO for now, and DMA will be supported eventually. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-sun6i.txt | 24 + drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi-sun6i.c | 483 ++++++++++++++++++ 4 files changed, 514 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-sun6i.txt create mode 100644 drivers/spi/spi-sun6i.c diff --git a/Documentation/devicetree/bindings/spi/spi-sun6i.txt b/Documentation/devicetree/bindings/spi/spi-sun6i.txt new file mode 100644 index 000000000000..21de73db6a05 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sun6i.txt @@ -0,0 +1,24 @@ +Allwinner A31 SPI controller + +Required properties: +- compatible: Should be "allwinner,sun6i-a31-spi". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clocks: phandle to the clocks feeding the SPI controller. Two are + needed: + - "ahb": the gated AHB parent clock + - "mod": the parent module clock +- clock-names: Must contain the clock names described just above +- resets: phandle to the reset controller asserting this device in + reset + +Example: + +spi1: spi@01c69000 { + compatible = "allwinner,sun6i-a31-spi"; + reg = <0x01c69000 0x1000>; + interrupts = <0 66 4>; + clocks = <&ahb1_gates 21>, <&spi1_clk>; + clock-names = "ahb", "mod"; + resets = <&ahb1_rst 21>; +}; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..7cfe0eed8dfa 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -446,6 +446,12 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_SUN6I + tristate "Allwinner A31 SPI controller" + depends on ARCH_SUNXI || COMPILE_TEST + help + This enables using the SPI controller on the Allwinner A31 SoCs. + config SPI_MXS tristate "Freescale MXS SPI controller" depends on ARCH_MXS diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 95af48d2d360..13b6ccf904d9 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o +obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c new file mode 100644 index 000000000000..94d38d0a86cd --- /dev/null +++ b/drivers/spi/spi-sun6i.c @@ -0,0 +1,483 @@ +/* + * Copyright (C) 2012 - 2014 Allwinner Tech + * Pan Nan + * + * Copyright (C) 2014 Maxime Ripard + * Maxime Ripard + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SUN6I_FIFO_DEPTH 128 + +#define SUN6I_GBL_CTL_REG 0x04 +#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0) +#define SUN6I_GBL_CTL_MASTER BIT(1) +#define SUN6I_GBL_CTL_TP BIT(7) +#define SUN6I_GBL_CTL_RST BIT(31) + +#define SUN6I_TFR_CTL_REG 0x08 +#define SUN6I_TFR_CTL_CPHA BIT(0) +#define SUN6I_TFR_CTL_CPOL BIT(1) +#define SUN6I_TFR_CTL_SPOL BIT(2) +#define SUN6I_TFR_CTL_CS_MASK 0x3 +#define SUN6I_TFR_CTL_CS(cs) (((cs) & SUN6I_TFR_CTL_CS_MASK) << 4) +#define SUN6I_TFR_CTL_CS_MANUAL BIT(6) +#define SUN6I_TFR_CTL_CS_LEVEL BIT(7) +#define SUN6I_TFR_CTL_DHB BIT(8) +#define SUN6I_TFR_CTL_FBS BIT(12) +#define SUN6I_TFR_CTL_XCH BIT(31) + +#define SUN6I_INT_CTL_REG 0x10 +#define SUN6I_INT_CTL_RF_OVF BIT(8) +#define SUN6I_INT_CTL_TC BIT(12) + +#define SUN6I_INT_STA_REG 0x14 + +#define SUN6I_FIFO_CTL_REG 0x18 +#define SUN6I_FIFO_CTL_RF_RST BIT(15) +#define SUN6I_FIFO_CTL_TF_RST BIT(31) + +#define SUN6I_FIFO_STA_REG 0x1c +#define SUN6I_FIFO_STA_RF_CNT_MASK 0x7f +#define SUN6I_FIFO_STA_RF_CNT_BITS 0 +#define SUN6I_FIFO_STA_TF_CNT_MASK 0x7f +#define SUN6I_FIFO_STA_TF_CNT_BITS 16 + +#define SUN6I_CLK_CTL_REG 0x24 +#define SUN6I_CLK_CTL_CDR2_MASK 0xff +#define SUN6I_CLK_CTL_CDR2(div) (((div) & SUN6I_CLK_CTL_CDR2_MASK) << 0) +#define SUN6I_CLK_CTL_CDR1_MASK 0xf +#define SUN6I_CLK_CTL_CDR1(div) (((div) & SUN6I_CLK_CTL_CDR1_MASK) << 8) +#define SUN6I_CLK_CTL_DRS BIT(12) + +#define SUN6I_BURST_CNT_REG 0x30 +#define SUN6I_BURST_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN6I_XMIT_CNT_REG 0x34 +#define SUN6I_XMIT_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN6I_BURST_CTL_CNT_REG 0x38 +#define SUN6I_BURST_CTL_CNT_STC(cnt) ((cnt) & 0xffffff) + +#define SUN6I_TXDATA_REG 0x200 +#define SUN6I_RXDATA_REG 0x300 + +struct sun6i_spi { + struct spi_master *master; + void __iomem *base_addr; + struct clk *hclk; + struct clk *mclk; + struct reset_control *rstc; + + struct completion done; + + const u8 *tx_buf; + u8 *rx_buf; + int len; +}; + +static inline u32 sun6i_spi_read(struct sun6i_spi *sspi, u32 reg) +{ + return readl(sspi->base_addr + reg); +} + +static inline void sun6i_spi_write(struct sun6i_spi *sspi, u32 reg, u32 value) +{ + writel(value, sspi->base_addr + reg); +} + +static inline void sun6i_spi_drain_fifo(struct sun6i_spi *sspi, int len) +{ + u32 reg, cnt; + u8 byte; + + /* See how much data is available */ + reg = sun6i_spi_read(sspi, SUN6I_FIFO_STA_REG); + reg &= SUN6I_FIFO_STA_RF_CNT_MASK; + cnt = reg >> SUN6I_FIFO_STA_RF_CNT_BITS; + + if (len > cnt) + len = cnt; + + while (len--) { + byte = readb(sspi->base_addr + SUN6I_RXDATA_REG); + if (sspi->rx_buf) + *sspi->rx_buf++ = byte; + } +} + +static inline void sun6i_spi_fill_fifo(struct sun6i_spi *sspi, int len) +{ + u8 byte; + + if (len > sspi->len) + len = sspi->len; + + while (len--) { + byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; + writeb(byte, sspi->base_addr + SUN6I_TXDATA_REG); + sspi->len--; + } +} + +static void sun6i_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct sun6i_spi *sspi = spi_master_get_devdata(spi->master); + u32 reg; + + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); + reg &= ~SUN6I_TFR_CTL_CS_MASK; + reg |= SUN6I_TFR_CTL_CS(spi->chip_select); + + if (enable) + reg |= SUN6I_TFR_CTL_CS_LEVEL; + else + reg &= ~SUN6I_TFR_CTL_CS_LEVEL; + + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); +} + + +static int sun6i_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct sun6i_spi *sspi = spi_master_get_devdata(master); + unsigned int mclk_rate, div, timeout; + unsigned int tx_len = 0; + int ret = 0; + u32 reg; + + /* We don't support transfer larger than the FIFO */ + if (tfr->len > SUN6I_FIFO_DEPTH) + return -EINVAL; + + reinit_completion(&sspi->done); + sspi->tx_buf = tfr->tx_buf; + sspi->rx_buf = tfr->rx_buf; + sspi->len = tfr->len; + + /* Clear pending interrupts */ + sun6i_spi_write(sspi, SUN6I_INT_STA_REG, ~0); + + /* Reset FIFO */ + sun6i_spi_write(sspi, SUN6I_FIFO_CTL_REG, + SUN6I_FIFO_CTL_RF_RST | SUN6I_FIFO_CTL_TF_RST); + + /* + * Setup the transfer control register: Chip Select, + * polarities, etc. + */ + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); + + if (spi->mode & SPI_CPOL) + reg |= SUN6I_TFR_CTL_CPOL; + else + reg &= ~SUN6I_TFR_CTL_CPOL; + + if (spi->mode & SPI_CPHA) + reg |= SUN6I_TFR_CTL_CPHA; + else + reg &= ~SUN6I_TFR_CTL_CPHA; + + if (spi->mode & SPI_LSB_FIRST) + reg |= SUN6I_TFR_CTL_FBS; + else + reg &= ~SUN6I_TFR_CTL_FBS; + + /* + * If it's a TX only transfer, we don't want to fill the RX + * FIFO with bogus data + */ + if (sspi->rx_buf) + reg &= ~SUN6I_TFR_CTL_DHB; + else + reg |= SUN6I_TFR_CTL_DHB; + + /* We want to control the chip select manually */ + reg |= SUN6I_TFR_CTL_CS_MANUAL; + + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg); + + /* Ensure that we have a parent clock fast enough */ + mclk_rate = clk_get_rate(sspi->mclk); + if (mclk_rate < (2 * spi->max_speed_hz)) { + clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz); + mclk_rate = clk_get_rate(sspi->mclk); + } + + /* + * Setup clock divider. + * + * We have two choices there. Either we can use the clock + * divide rate 1, which is calculated thanks to this formula: + * SPI_CLK = MOD_CLK / (2 ^ cdr) + * Or we can use CDR2, which is calculated with the formula: + * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) + * Wether we use the former or the latter is set through the + * DRS bit. + * + * First try CDR2, and if we can't reach the expected + * frequency, fall back to CDR1. + */ + div = mclk_rate / (2 * spi->max_speed_hz); + if (div <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) { + if (div > 0) + div--; + + reg = SUN6I_CLK_CTL_CDR2(div) | SUN6I_CLK_CTL_DRS; + } else { + div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz); + reg = SUN6I_CLK_CTL_CDR1(div); + } + + sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg); + + /* Setup the transfer now... */ + if (sspi->tx_buf) + tx_len = tfr->len; + + /* Setup the counters */ + sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, SUN6I_BURST_CNT(tfr->len)); + sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, SUN6I_XMIT_CNT(tx_len)); + sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, + SUN6I_BURST_CTL_CNT_STC(tx_len)); + + /* Fill the TX FIFO */ + sun6i_spi_fill_fifo(sspi, SUN6I_FIFO_DEPTH); + + /* Enable the interrupts */ + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, SUN6I_INT_CTL_TC); + + /* Start the transfer */ + reg = sun6i_spi_read(sspi, SUN6I_TFR_CTL_REG); + sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg | SUN6I_TFR_CTL_XCH); + + timeout = wait_for_completion_timeout(&sspi->done, + msecs_to_jiffies(1000)); + if (!timeout) { + ret = -ETIMEDOUT; + goto out; + } + + sun6i_spi_drain_fifo(sspi, SUN6I_FIFO_DEPTH); + +out: + sun6i_spi_write(sspi, SUN6I_INT_CTL_REG, 0); + + return ret; +} + +static irqreturn_t sun6i_spi_handler(int irq, void *dev_id) +{ + struct sun6i_spi *sspi = dev_id; + u32 status = sun6i_spi_read(sspi, SUN6I_INT_STA_REG); + + /* Transfer complete */ + if (status & SUN6I_INT_CTL_TC) { + sun6i_spi_write(sspi, SUN6I_INT_STA_REG, SUN6I_INT_CTL_TC); + complete(&sspi->done); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int sun6i_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun6i_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = clk_prepare_enable(sspi->hclk); + if (ret) { + dev_err(dev, "Couldn't enable AHB clock\n"); + goto out; + } + + ret = clk_prepare_enable(sspi->mclk); + if (ret) { + dev_err(dev, "Couldn't enable module clock\n"); + goto err; + } + + ret = reset_control_deassert(sspi->rstc); + if (ret) { + dev_err(dev, "Couldn't deassert the device from reset\n"); + goto err2; + } + + sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, + SUN6I_GBL_CTL_BUS_ENABLE | SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP); + + return 0; + +err2: + clk_disable_unprepare(sspi->mclk); +err: + clk_disable_unprepare(sspi->hclk); +out: + return ret; +} + +static int sun6i_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun6i_spi *sspi = spi_master_get_devdata(master); + + reset_control_assert(sspi->rstc); + clk_disable_unprepare(sspi->mclk); + clk_disable_unprepare(sspi->hclk); + + return 0; +} + +static int sun6i_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct sun6i_spi *sspi; + struct resource *res; + int ret = 0, irq; + + master = spi_alloc_master(&pdev->dev, sizeof(struct sun6i_spi)); + if (!master) { + dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, master); + sspi = spi_master_get_devdata(master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sspi->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sspi->base_addr)) { + ret = PTR_ERR(sspi->base_addr); + goto err_free_master; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No spi IRQ specified\n"); + ret = -ENXIO; + goto err_free_master; + } + + ret = devm_request_irq(&pdev->dev, irq, sun6i_spi_handler, + 0, "sun6i-spi", sspi); + if (ret) { + dev_err(&pdev->dev, "Cannot request IRQ\n"); + goto err_free_master; + } + + sspi->master = master; + master->set_cs = sun6i_spi_set_cs; + master->transfer_one = sun6i_spi_transfer_one; + master->num_chipselect = 4; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + master->dev.of_node = pdev->dev.of_node; + master->auto_runtime_pm = true; + + sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sspi->hclk)) { + dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); + ret = PTR_ERR(sspi->hclk); + goto err_free_master; + } + + sspi->mclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(sspi->mclk)) { + dev_err(&pdev->dev, "Unable to acquire module clock\n"); + ret = PTR_ERR(sspi->mclk); + goto err_free_master; + } + + init_completion(&sspi->done); + + sspi->rstc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(sspi->rstc)) { + dev_err(&pdev->dev, "Couldn't get reset controller\n"); + ret = PTR_ERR(sspi->rstc); + goto err_free_master; + } + + /* + * This wake-up/shutdown pattern is to be able to have the + * device woken up, even if runtime_pm is disabled + */ + ret = sun6i_spi_runtime_resume(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't resume the device\n"); + goto err_free_master; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI master\n"); + goto err_pm_disable; + } + + return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + sun6i_spi_runtime_suspend(&pdev->dev); +err_free_master: + spi_master_put(master); + return ret; +} + +static int sun6i_spi_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id sun6i_spi_match[] = { + { .compatible = "allwinner,sun6i-a31-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, sun6i_spi_match); + +static const struct dev_pm_ops sun6i_spi_pm_ops = { + .runtime_resume = sun6i_spi_runtime_resume, + .runtime_suspend = sun6i_spi_runtime_suspend, +}; + +static struct platform_driver sun6i_spi_driver = { + .probe = sun6i_spi_probe, + .remove = sun6i_spi_remove, + .driver = { + .name = "sun6i-spi", + .owner = THIS_MODULE, + .of_match_table = sun6i_spi_match, + .pm = &sun6i_spi_pm_ops, + }, +}; +module_platform_driver(sun6i_spi_driver); + +MODULE_AUTHOR("Pan Nan "); +MODULE_AUTHOR("Maxime Ripard "); +MODULE_DESCRIPTION("Allwinner A31 SPI controller driver"); +MODULE_LICENSE("GPL"); From 91cfe7e73b484703baf353d3915823210a417d77 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 6 Feb 2014 10:52:21 +0800 Subject: [PATCH 041/201] spi: davinci: Remove unneeded NULL checking for dspi and dspi->bitbang.master spi_master_get_devdata() never returns NULL when spi_alloc_master() success, so remove NULL test for dspi. We have ensured master is not NULL before assigning it to dspi->bitbang.master. So also remove NULL test for dspi->bitbang.master. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 5e7389faa2a0..04d69b650328 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -864,10 +864,6 @@ static int davinci_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); dspi = spi_master_get_devdata(master); - if (dspi == NULL) { - ret = -ENOENT; - goto free_master; - } if (dev_get_platdata(&pdev->dev)) { pdata = dev_get_platdata(&pdev->dev); @@ -908,10 +904,6 @@ static int davinci_spi_probe(struct platform_device *pdev) goto free_master; dspi->bitbang.master = master; - if (dspi->bitbang.master == NULL) { - ret = -ENODEV; - goto free_master; - } dspi->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dspi->clk)) { From b53b34f042fe17df21a431abc76896a72dbc5670 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 6 Feb 2014 11:45:08 +0800 Subject: [PATCH 042/201] spi: davinci: Use of_match_ptr at appropriate place It's pointless to use of_match_ptr within CONFIG_OF guard. Use of_match_ptr around davinci_spi_of_match when setting .of_match_table. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-davinci.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index 04d69b650328..50f750989258 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -802,8 +802,7 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, pdata = &dspi->pdata; pdata->version = SPI_VERSION_1; - match = of_match_device(of_match_ptr(davinci_spi_of_match), - &pdev->dev); + match = of_match_device(davinci_spi_of_match, &pdev->dev); if (!match) return -ENODEV; @@ -824,7 +823,6 @@ static int spi_davinci_get_pdata(struct platform_device *pdev, return 0; } #else -#define davinci_spi_of_match NULL static struct davinci_spi_platform_data *spi_davinci_get_pdata(struct platform_device *pdev, struct davinci_spi *dspi) @@ -1032,7 +1030,7 @@ static struct platform_driver davinci_spi_driver = { .driver = { .name = "spi_davinci", .owner = THIS_MODULE, - .of_match_table = davinci_spi_of_match, + .of_match_table = of_match_ptr(davinci_spi_of_match), }, .probe = davinci_spi_probe, .remove = davinci_spi_remove, From 1647138df66c695eb16f4a6bce7f088f817ab26d Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Wed, 5 Feb 2014 22:23:01 +0100 Subject: [PATCH 043/201] spi: orion: Remove unused pointer in orion_spi_write_read() Remove unused devdata pointer 'orion_spi' in function orion_spi_write_read(). Detected by Coverity: CID 1077860. Signed-off-by: Christian Engelmayer Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 7f2121fe2622..75871d444ff4 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -260,11 +260,9 @@ orion_spi_write_read_16bit(struct spi_device *spi, static unsigned int orion_spi_write_read(struct spi_device *spi, struct spi_transfer *xfer) { - struct orion_spi *orion_spi; unsigned int count; int word_len; - orion_spi = spi_master_get_devdata(spi->master); word_len = spi->bits_per_word; count = xfer->len; From 7961656a6f11b69966500d7bd25273203fd930da Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 6 Feb 2014 10:53:51 +0000 Subject: [PATCH 044/201] spi/sunxi: Add missing dependency on RESET_CONTROLLER Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 7cfe0eed8dfa..0ec46415145d 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -449,6 +449,7 @@ config SPI_SIRF config SPI_SUN6I tristate "Allwinner A31 SPI controller" depends on ARCH_SUNXI || COMPILE_TEST + depends on RESET_CONTROLLER help This enables using the SPI controller on the Allwinner A31 SoCs. From b52a37f517d62c92d7d5bffb0fab0b025a51b9eb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Feb 2014 11:05:50 +0800 Subject: [PATCH 045/201] spi: orion: Let spi core handle checking transfer speed Since commit a2fd4f9fa3b9 'spi: Support transfer speed checking in the core', the SPI core validates the desired speed of a given transfer against the minimum and maximum speeds supported by the controller. So we can remove the same code in this driver and let spi core handle checking the desired speed of a given transfer. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 75871d444ff4..20f174ee06ec 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -43,8 +43,6 @@ struct orion_spi { struct spi_master *master; void __iomem *base; - unsigned int max_speed; - unsigned int min_speed; struct clk *clk; }; @@ -319,16 +317,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master, goto msg_done; } - if (t->speed_hz && t->speed_hz < orion_spi->min_speed) { - dev_err(&spi->dev, - "message rejected : " - "device min speed (%d Hz) exceeds " - "required transfer speed (%d Hz)\n", - orion_spi->min_speed, t->speed_hz); - status = -EIO; - goto msg_done; - } - if (par_override || t->speed_hz || t->bits_per_word) { par_override = 1; status = orion_spi_setup_transfer(spi, t); @@ -373,28 +361,6 @@ static int orion_spi_reset(struct orion_spi *orion_spi) return 0; } -static int orion_spi_setup(struct spi_device *spi) -{ - struct orion_spi *orion_spi; - - orion_spi = spi_master_get_devdata(spi->master); - - if ((spi->max_speed_hz == 0) - || (spi->max_speed_hz > orion_spi->max_speed)) - spi->max_speed_hz = orion_spi->max_speed; - - if (spi->max_speed_hz < orion_spi->min_speed) { - dev_err(&spi->dev, "setup: requested speed too low %d Hz\n", - spi->max_speed_hz); - return -EINVAL; - } - - /* - * baudrate & width will be set orion_spi_setup_transfer - */ - return 0; -} - static int orion_spi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -423,7 +389,6 @@ static int orion_spi_probe(struct platform_device *pdev) /* we support only mode 0, and no options */ master->mode_bits = SPI_CPHA | SPI_CPOL; - master->setup = orion_spi_setup; master->transfer_one_message = orion_spi_transfer_one_message; master->num_chipselect = ORION_NUM_CHIPSELECTS; @@ -441,8 +406,8 @@ static int orion_spi_probe(struct platform_device *pdev) clk_prepare(spi->clk); clk_enable(spi->clk); tclk_hz = clk_get_rate(spi->clk); - spi->max_speed = DIV_ROUND_UP(tclk_hz, 4); - spi->min_speed = DIV_ROUND_UP(tclk_hz, 30); + master->max_speed_hz = DIV_ROUND_UP(tclk_hz, 4); + master->min_speed_hz = DIV_ROUND_UP(tclk_hz, 30); r = platform_get_resource(pdev, IORESOURCE_MEM, 0); spi->base = devm_ioremap_resource(&pdev->dev, r); From 9a7da6cc1d952b70284e34a594486045eadba8d5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Feb 2014 17:47:59 +0800 Subject: [PATCH 046/201] spi: mxs: Use list_for_each_entry to iterate over transfer list We don't modify the list entry while iterating the transfer list. So use list_for_each_entry instead of list_for_each_entry_safe. Signed-off-by: Axel Lin Acked-by: Marek Vasut Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index 79e5aa2250c8..d3803198e166 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -371,7 +371,7 @@ static int mxs_spi_transfer_one(struct spi_master *master, { struct mxs_spi *spi = spi_master_get_devdata(master); struct mxs_ssp *ssp = &spi->ssp; - struct spi_transfer *t, *tmp_t; + struct spi_transfer *t; unsigned int flag; int status = 0; @@ -381,7 +381,7 @@ static int mxs_spi_transfer_one(struct spi_master *master, writel(mxs_spi_cs_to_reg(m->spi->chip_select), ssp->base + HW_SSP_CTRL0 + STMP_OFFSET_REG_SET); - list_for_each_entry_safe(t, tmp_t, &m->transfers, transfer_list) { + list_for_each_entry(t, &m->transfers, transfer_list) { status = mxs_spi_setup_transfer(m->spi, t); if (status) From aa188f90ff1a82fa8f848092ff4969dba78b275f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Feb 2014 21:59:18 +0800 Subject: [PATCH 047/201] spi: Use SPI_BPW_MASK macro at appropriate places Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-bfin-v3.c | 3 ++- drivers/spi/spi-ti-qspi.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-bfin-v3.c b/drivers/spi/spi-bfin-v3.c index 8f8598834b30..4089d0e0d84e 100644 --- a/drivers/spi/spi-bfin-v3.c +++ b/drivers/spi/spi-bfin-v3.c @@ -822,7 +822,8 @@ static int bfin_spi_probe(struct platform_device *pdev) master->cleanup = bfin_spi_cleanup; master->setup = bfin_spi_setup; master->transfer_one_message = bfin_spi_transfer_one_message; - master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | + SPI_BPW_MASK(8); drv_data = spi_master_get_devdata(master); drv_data->master = master; diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 3d09265b5133..7eb2cef739b6 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -435,7 +435,8 @@ static int ti_qspi_probe(struct platform_device *pdev) master->auto_runtime_pm = true; master->transfer_one_message = ti_qspi_start_transfer_one; master->dev.of_node = pdev->dev.of_node; - master->bits_per_word_mask = BIT(32 - 1) | BIT(16 - 1) | BIT(8 - 1); + master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | + SPI_BPW_MASK(8); if (!of_property_read_u32(np, "num-cs", &num_cs)) master->num_chipselect = num_cs; From 3f29588795bdd0d48f0ecc94e3ee06c128ca3300 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 16 Jan 2014 12:25:46 +0000 Subject: [PATCH 048/201] spi/s3c64xx: Use core DMA mapping code with dmaengine When using dmaengine allow the core to do the DMA mapping. We still need local mapping code for the non-dmaengine case so this doesn't save us anything for now. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 178 ++++++++++++++++++++++---------------- 1 file changed, 103 insertions(+), 75 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 25c9bd409a87..4490e8c499c0 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -291,6 +291,81 @@ static struct s3c2410_dma_client s3c64xx_spi_dma_client = { .name = "samsung-spi-dma", }; +static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ + struct device *dev = &sdd->pdev->dev; + struct spi_transfer *xfer; + + if (is_polling(sdd) || msg->is_dma_mapped) + return 0; + + /* First mark all xfer unmapped */ + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + xfer->rx_dma = XFER_DMAADDR_INVALID; + xfer->tx_dma = XFER_DMAADDR_INVALID; + } + + /* Map until end or first fail */ + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + + if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) + continue; + + if (xfer->tx_buf != NULL) { + xfer->tx_dma = dma_map_single(dev, + (void *)xfer->tx_buf, xfer->len, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, xfer->tx_dma)) { + dev_err(dev, "dma_map_single Tx failed\n"); + xfer->tx_dma = XFER_DMAADDR_INVALID; + return -ENOMEM; + } + } + + if (xfer->rx_buf != NULL) { + xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, + xfer->len, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, xfer->rx_dma)) { + dev_err(dev, "dma_map_single Rx failed\n"); + dma_unmap_single(dev, xfer->tx_dma, + xfer->len, DMA_TO_DEVICE); + xfer->tx_dma = XFER_DMAADDR_INVALID; + xfer->rx_dma = XFER_DMAADDR_INVALID; + return -ENOMEM; + } + } + } + + return 0; +} + +static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ + struct device *dev = &sdd->pdev->dev; + struct spi_transfer *xfer; + + if (is_polling(sdd) || msg->is_dma_mapped) + return; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + + if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) + continue; + + if (xfer->rx_buf != NULL + && xfer->rx_dma != XFER_DMAADDR_INVALID) + dma_unmap_single(dev, xfer->rx_dma, + xfer->len, DMA_FROM_DEVICE); + + if (xfer->tx_buf != NULL + && xfer->tx_dma != XFER_DMAADDR_INVALID) + dma_unmap_single(dev, xfer->tx_dma, + xfer->len, DMA_TO_DEVICE); + } +} + static void prepare_dma(struct s3c64xx_spi_dma_data *dma, unsigned len, dma_addr_t buf) { @@ -378,8 +453,22 @@ static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, { sdd->ops->stop((enum dma_ch)dma->ch); } + +#define s3c64xx_spi_can_dma NULL + #else +static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ + return 0; +} + +static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, + struct spi_message *msg) +{ +} + static void prepare_dma(struct s3c64xx_spi_dma_data *dma, struct sg_table *sgt) { @@ -437,6 +526,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) ret = -EBUSY; goto out; } + spi->dma_rx = sdd->rx_dma.ch; sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter, (void *)sdd->tx_dma.dmach, dev, "tx"); @@ -445,6 +535,7 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) ret = -EBUSY; goto out_rx; } + spi->dma_tx = sdd->tx_dma.ch; } ret = pm_runtime_get_sync(&sdd->pdev->dev); @@ -482,6 +573,16 @@ static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, { dmaengine_terminate_all(dma->ch); } + +static bool s3c64xx_spi_can_dma(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); + + return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; +} + #endif static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, @@ -764,81 +865,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd) #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32) -static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return 0; - - /* First mark all xfer unmapped */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - xfer->rx_dma = XFER_DMAADDR_INVALID; - xfer->tx_dma = XFER_DMAADDR_INVALID; - } - - /* Map until end or first fail */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->tx_buf != NULL) { - xfer->tx_dma = dma_map_single(dev, - (void *)xfer->tx_buf, xfer->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, xfer->tx_dma)) { - dev_err(dev, "dma_map_single Tx failed\n"); - xfer->tx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - - if (xfer->rx_buf != NULL) { - xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, - xfer->len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, xfer->rx_dma)) { - dev_err(dev, "dma_map_single Rx failed\n"); - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - xfer->tx_dma = XFER_DMAADDR_INVALID; - xfer->rx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - } - - return 0; -} - -static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->rx_buf != NULL - && xfer->rx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->rx_dma, - xfer->len, DMA_FROM_DEVICE); - - if (xfer->tx_buf != NULL - && xfer->tx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - } -} - static int s3c64xx_spi_prepare_message(struct spi_master *master, struct spi_message *msg) { @@ -1338,6 +1364,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->auto_runtime_pm = true; + if (!is_polling(sdd)) + master->can_dma = s3c64xx_spi_can_dma; sdd->regs = devm_ioremap_resource(&pdev->dev, mem_res); if (IS_ERR(sdd->regs)) { From 90e73973d3e48b3f6b37ea944fdef8e1543d36fc Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 7 Feb 2014 12:34:36 +0000 Subject: [PATCH 049/201] spi/s3c64xx: Remove S3C_DMA support All the platforms which use the old S3C_DMA API have now been converted to dmaengine so we can remove the legacy code from the driver, simplifying maintenance. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 191 -------------------------------------- 1 file changed, 191 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 4490e8c499c0..18ec7e65a319 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -34,10 +34,6 @@ #include -#ifdef CONFIG_S3C_DMA -#include -#endif - #define MAX_SPI_PORTS 3 #define S3C64XX_SPI_QUIRK_POLL (1 << 0) @@ -200,9 +196,6 @@ struct s3c64xx_spi_driver_data { unsigned cur_speed; struct s3c64xx_spi_dma_data rx_dma; struct s3c64xx_spi_dma_data tx_dma; -#ifdef CONFIG_S3C_DMA - struct samsung_dma_ops *ops; -#endif struct s3c64xx_spi_port_config *port_conf; unsigned int port_id; bool cs_gpio; @@ -284,180 +277,6 @@ static void s3c64xx_spi_dmacb(void *data) spin_unlock_irqrestore(&sdd->lock, flags); } -#ifdef CONFIG_S3C_DMA -/* FIXME: remove this section once arch/arm/mach-s3c64xx uses dmaengine */ - -static struct s3c2410_dma_client s3c64xx_spi_dma_client = { - .name = "samsung-spi-dma", -}; - -static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return 0; - - /* First mark all xfer unmapped */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - xfer->rx_dma = XFER_DMAADDR_INVALID; - xfer->tx_dma = XFER_DMAADDR_INVALID; - } - - /* Map until end or first fail */ - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->tx_buf != NULL) { - xfer->tx_dma = dma_map_single(dev, - (void *)xfer->tx_buf, xfer->len, - DMA_TO_DEVICE); - if (dma_mapping_error(dev, xfer->tx_dma)) { - dev_err(dev, "dma_map_single Tx failed\n"); - xfer->tx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - - if (xfer->rx_buf != NULL) { - xfer->rx_dma = dma_map_single(dev, xfer->rx_buf, - xfer->len, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, xfer->rx_dma)) { - dev_err(dev, "dma_map_single Rx failed\n"); - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - xfer->tx_dma = XFER_DMAADDR_INVALID; - xfer->rx_dma = XFER_DMAADDR_INVALID; - return -ENOMEM; - } - } - } - - return 0; -} - -static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - struct device *dev = &sdd->pdev->dev; - struct spi_transfer *xfer; - - if (is_polling(sdd) || msg->is_dma_mapped) - return; - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - - if (xfer->len <= ((FIFO_LVL_MASK(sdd) >> 1) + 1)) - continue; - - if (xfer->rx_buf != NULL - && xfer->rx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->rx_dma, - xfer->len, DMA_FROM_DEVICE); - - if (xfer->tx_buf != NULL - && xfer->tx_dma != XFER_DMAADDR_INVALID) - dma_unmap_single(dev, xfer->tx_dma, - xfer->len, DMA_TO_DEVICE); - } -} - -static void prepare_dma(struct s3c64xx_spi_dma_data *dma, - unsigned len, dma_addr_t buf) -{ - struct s3c64xx_spi_driver_data *sdd; - struct samsung_dma_prep info; - struct samsung_dma_config config; - - if (dma->direction == DMA_DEV_TO_MEM) { - sdd = container_of((void *)dma, - struct s3c64xx_spi_driver_data, rx_dma); - config.direction = sdd->rx_dma.direction; - config.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA; - config.width = sdd->cur_bpw / 8; - sdd->ops->config((enum dma_ch)sdd->rx_dma.ch, &config); - } else { - sdd = container_of((void *)dma, - struct s3c64xx_spi_driver_data, tx_dma); - config.direction = sdd->tx_dma.direction; - config.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA; - config.width = sdd->cur_bpw / 8; - sdd->ops->config((enum dma_ch)sdd->tx_dma.ch, &config); - } - - info.cap = DMA_SLAVE; - info.len = len; - info.fp = s3c64xx_spi_dmacb; - info.fp_param = dma; - info.direction = dma->direction; - info.buf = buf; - - sdd->ops->prepare((enum dma_ch)dma->ch, &info); - sdd->ops->trigger((enum dma_ch)dma->ch); -} - -static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) -{ - struct samsung_dma_req req; - struct device *dev = &sdd->pdev->dev; - - sdd->ops = samsung_dma_get_ops(); - - req.cap = DMA_SLAVE; - req.client = &s3c64xx_spi_dma_client; - - sdd->rx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request( - sdd->rx_dma.dmach, &req, dev, "rx"); - sdd->tx_dma.ch = (struct dma_chan *)(unsigned long)sdd->ops->request( - sdd->tx_dma.dmach, &req, dev, "tx"); - - return 1; -} - -static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* - * If DMA resource was not available during - * probe, no need to continue with dma requests - * else Acquire DMA channels - */ - while (!is_polling(sdd) && !acquire_dma(sdd)) - usleep_range(10000, 11000); - - return 0; -} - -static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - - /* Free DMA channels */ - if (!is_polling(sdd)) { - sdd->ops->release((enum dma_ch)sdd->rx_dma.ch, - &s3c64xx_spi_dma_client); - sdd->ops->release((enum dma_ch)sdd->tx_dma.ch, - &s3c64xx_spi_dma_client); - } - - return 0; -} - -static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, - struct s3c64xx_spi_dma_data *dma) -{ - sdd->ops->stop((enum dma_ch)dma->ch); -} - -#define s3c64xx_spi_can_dma NULL - -#else - static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, struct spi_message *msg) { @@ -583,8 +402,6 @@ static bool s3c64xx_spi_can_dma(struct spi_master *master, return xfer->len > (FIFO_LVL_MASK(sdd) >> 1) + 1; } -#endif - static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, struct spi_device *spi, struct spi_transfer *xfer, int dma_mode) @@ -616,11 +433,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, chcfg |= S3C64XX_SPI_CH_TXCH_ON; if (dma_mode) { modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; -#ifndef CONFIG_S3C_DMA prepare_dma(&sdd->tx_dma, &xfer->tx_sg); -#else - prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma); -#endif } else { switch (sdd->cur_bpw) { case 32: @@ -652,11 +465,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) | S3C64XX_SPI_PACKET_CNT_EN, regs + S3C64XX_SPI_PACKET_CNT); -#ifndef CONFIG_S3C_DMA prepare_dma(&sdd->rx_dma, &xfer->rx_sg); -#else - prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma); -#endif } } From 1b5e1b694919ee13b9ae6e5c6727363103e6f7f2 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 7 Feb 2014 12:39:22 +0000 Subject: [PATCH 050/201] spi/s3c64xx: Remove code no longer needed as a result of S3C_DMA removal Remove functions that only had an effect when using S3C_DMA and inline dmaengine_terminate_all() since it's pointless to have a function which expands to a single function call. Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 18ec7e65a319..9ad5e3e76b96 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -277,17 +277,6 @@ static void s3c64xx_spi_dmacb(void *data) spin_unlock_irqrestore(&sdd->lock, flags); } -static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ - return 0; -} - -static void s3c64xx_spi_unmap_mssg(struct s3c64xx_spi_driver_data *sdd, - struct spi_message *msg) -{ -} - static void prepare_dma(struct s3c64xx_spi_dma_data *dma, struct sg_table *sgt) { @@ -387,12 +376,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) return 0; } -static void s3c64xx_spi_dma_stop(struct s3c64xx_spi_driver_data *sdd, - struct s3c64xx_spi_dma_data *dma) -{ - dmaengine_terminate_all(dma->ch); -} - static bool s3c64xx_spi_can_dma(struct spi_master *master, struct spi_device *spi, struct spi_transfer *xfer) @@ -691,13 +674,6 @@ static int s3c64xx_spi_prepare_message(struct spi_master *master, s3c64xx_spi_config(sdd); } - /* Map all the transfers if needed */ - if (s3c64xx_spi_map_mssg(sdd, msg)) { - dev_err(&spi->dev, - "Xfer: Unable to map message buffers!\n"); - return -ENOMEM; - } - /* Configure feedback delay */ writel(cs->fb_delay & 0x3, sdd->regs + S3C64XX_SPI_FB_CLK); @@ -769,10 +745,10 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, if (use_dma) { if (xfer->tx_buf != NULL && (sdd->state & TXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->tx_dma); + dmaengine_terminate_all(sdd->tx_dma.ch); if (xfer->rx_buf != NULL && (sdd->state & RXBUSY)) - s3c64xx_spi_dma_stop(sdd, &sdd->rx_dma); + dmaengine_terminate_all(sdd->rx_dma.ch); } } else { flush_fifo(sdd); @@ -781,16 +757,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, return status; } -static int s3c64xx_spi_unprepare_message(struct spi_master *master, - struct spi_message *msg) -{ - struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); - - s3c64xx_spi_unmap_mssg(sdd, msg); - - return 0; -} - static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( struct spi_device *spi) { @@ -1164,7 +1130,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) master->prepare_transfer_hardware = s3c64xx_spi_prepare_transfer; master->prepare_message = s3c64xx_spi_prepare_message; master->transfer_one = s3c64xx_spi_transfer_one; - master->unprepare_message = s3c64xx_spi_unprepare_message; master->unprepare_transfer_hardware = s3c64xx_spi_unprepare_transfer; master->num_chipselect = sci->num_cs; master->dma_alignment = 8; From d655bbbd5beead3643f6769adaa1f30bcddc3fe2 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 8 Feb 2014 22:46:02 +0800 Subject: [PATCH 051/201] spi: omap-100k: Remove unused MOD_REG_BIT macro Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 0d32054bfc0d..657184a4644c 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -99,13 +99,6 @@ struct omap1_spi100k_cs { int word_len; }; -#define MOD_REG_BIT(val, mask, set) do { \ - if (set) \ - val |= mask; \ - else \ - val &= ~mask; \ -} while (0) - static void spi100k_enable_clock(struct spi_master *master) { unsigned int val; From 77c398f58c1fe57224c17f6d4360c7f74cc0e418 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Sat, 8 Feb 2014 19:02:23 +0100 Subject: [PATCH 052/201] spi: omap-100k: Remove unused pointer in omap1_spi100k_txrx_pio() Remove unused devdata pointer 'spi100k' in function omap1_spi100k_txrx_pio(). Detected by Coverity: CID 1077869. Signed-off-by: Christian Engelmayer Reviewed-by: Jingoo Han Acked-by: Michal Nazarewicz Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 657184a4644c..afc91c4d8461 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -197,12 +197,10 @@ static void omap1_spi100k_force_cs(struct omap1_spi100k *spi100k, int enable) static unsigned omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) { - struct omap1_spi100k *spi100k; struct omap1_spi100k_cs *cs = spi->controller_state; unsigned int count, c; int word_len; - spi100k = spi_master_get_devdata(spi->master); count = xfer->len; c = count; word_len = cs->word_len; From 79c2f49a2dfed00e51b41427ef89c5e67263a8c3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 9 Feb 2014 11:35:59 +0800 Subject: [PATCH 053/201] spi: omap-100k: Remove unused fields from struct omap1_spi100k Both *master and state are not really used, remove them. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index afc91c4d8461..3b8b36a144b4 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -83,15 +83,11 @@ #define SPI_SHUTDOWN 1 struct omap1_spi100k { - struct spi_master *master; struct clk *ick; struct clk *fck; /* Virtual base address of the controller */ void __iomem *base; - - /* State of the SPI */ - unsigned int state; }; struct omap1_spi100k_cs { @@ -425,7 +421,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); spi100k = spi_master_get_devdata(master); - spi100k->master = master; /* * The memory region base address is taken as the platform_data. @@ -452,8 +447,6 @@ static int omap1_spi100k_probe(struct platform_device *pdev) if (status < 0) goto err; - spi100k->state = SPI_RUNNING; - return status; err: From aa0fe82629f19efba5c870bc9be089a4f8056a75 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 9 Feb 2014 11:06:04 +0800 Subject: [PATCH 054/201] spi: Use reinit_completion at appropriate places Calling init_completion() once is enough. For the rest of the iterations, call reinit_completion() instead. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx-hsspi.c | 3 ++- drivers/spi/spi-bcm63xx.c | 3 ++- drivers/spi/spi-efm32.c | 3 ++- drivers/spi/spi-imx.c | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index b528f9fc8bc0..3ad3e0c59992 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -180,7 +180,7 @@ static int bcm63xx_hsspi_do_txrx(struct spi_device *spi, struct spi_transfer *t) while (pending > 0) { int curr_step = min_t(int, step_size, pending); - init_completion(&bs->done); + reinit_completion(&bs->done); if (tx) { memcpy_toio(bs->fifo + HSSPI_OPCODE_LEN, tx, curr_step); tx += curr_step; @@ -369,6 +369,7 @@ static int bcm63xx_hsspi_probe(struct platform_device *pdev) bs->fifo = (u8 __iomem *)(bs->regs + HSSPI_FIFO_REG(0)); mutex_init(&bs->bus_mutex); + init_completion(&bs->done); master->bus_num = HSSPI_BUS_NUM; master->num_chipselect = 8; diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 77286aef2adf..161c7910a818 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -169,7 +169,7 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *first, transfer_list); } - init_completion(&bs->done); + reinit_completion(&bs->done); /* Fill in the Message control register */ msg_ctl = (len << SPI_BYTE_CNT_SHIFT); @@ -353,6 +353,7 @@ static int bcm63xx_spi_probe(struct platform_device *pdev) } bs = spi_master_get_devdata(master); + init_completion(&bs->done); platform_set_drvdata(pdev, master); bs->pdev = pdev; diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index d4d3cc534792..03cbb5eb33d6 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -198,7 +198,7 @@ static int efm32_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) efm32_spi_filltx(ddata); - init_completion(&ddata->done); + reinit_completion(&ddata->done); efm32_spi_write32(ddata, REG_IF_TXBL | REG_IF_RXDATAV, REG_IEN); @@ -349,6 +349,7 @@ static int efm32_spi_probe(struct platform_device *pdev) ddata->bitbang.txrx_bufs = efm32_spi_txrx_bufs; spin_lock_init(&ddata->lock); + init_completion(&ddata->done); ddata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(ddata->clk)) { diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index a5474ef9d2a0..6bb0b693c98c 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -741,7 +741,7 @@ static int spi_imx_transfer(struct spi_device *spi, spi_imx->count = transfer->len; spi_imx->txfifo = 0; - init_completion(&spi_imx->xfer_done); + reinit_completion(&spi_imx->xfer_done); spi_imx_push(spi_imx); From f6ab395bfeb0ba8dd0397c24b76af00ed016f286 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sat, 8 Feb 2014 22:01:21 +0100 Subject: [PATCH 055/201] spi: omap2: use SUPERH, not SH Commit 0079aae0f1e6 ("spi: omap2: Add build dependencies for writel_relaxed()") added an optional Kconfig dependency on SH. That Kconfig symbol doesn't exist. Apparently SUPERH was intended. Use that. Signed-off-by: Paul Bolle Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..205dbfe97e55 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -307,7 +307,7 @@ config SPI_OMAP_UWIRE config SPI_OMAP24XX tristate "McSPI driver for OMAP" - depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SH + depends on ARM || ARM64 || AVR32 || HEXAGON || MIPS || SUPERH depends on ARCH_OMAP2PLUS || COMPILE_TEST help SPI master controller for OMAP24XX and later Multichannel SPI From 052eb2d49006fe53bc5f62a196dce23345d4a907 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 Feb 2014 00:08:05 +0800 Subject: [PATCH 056/201] spi: core: Set max_speed_hz of spi_device default to max_speed_hz of controller In __spi_validate(), xfer->speed_hz is set to be spi->max_speed_hz if it is not set for this transfer. However, if spi->max_speed_hz is also not set, xfer->speed_hz is 0. Some drivers (e.g. au1550, tegra114, tegra20-sflash, tegra20-slink, etc.) then use below code to avoid setting xfer->speed_hz to 0. /* Set speed to the spi max fequency if spi device has not set */ spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency; Let's handle it in spi core. If spi->max_speed_hz is not set, make it default to spi->master->max_speed_hz. So In __spi_validate() if both xfer->speed_hz and spi->max_speed_hz are not set, xfer->speed_hz will be set to spi->master->max_speed_hz. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 23756b0f9036..e727ddda78bf 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1599,6 +1599,9 @@ int spi_setup(struct spi_device *spi) if (!spi->bits_per_word) spi->bits_per_word = 8; + if (!spi->max_speed_hz) + spi->max_speed_hz = spi->master->max_speed_hz; + if (spi->master->setup) status = spi->master->setup(spi); From 425f96d2f635d7a1a101c916830ba7843a6d5a50 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 9 Feb 2014 12:15:07 +0800 Subject: [PATCH 057/201] spi: txx9: Convert to let spi core handle checking transfer speed By setting master->max_speed_hz and master->min_speed_hz, spi core will handle checking transfer speed. Then we can remove the same checking in this driver. Signed-off-by: Axel Lin Reviewed-by: Atsushi Nemoto Signed-off-by: Mark Brown --- drivers/spi/spi-txx9.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 6191ced514b2..523f13df52bb 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -80,7 +80,6 @@ struct txx9spi { void __iomem *membase; int baseclk; struct clk *clk; - u32 max_speed_hz, min_speed_hz; int last_chipselect; int last_chipselect_val; }; @@ -117,9 +116,7 @@ static int txx9spi_setup(struct spi_device *spi) { struct txx9spi *c = spi_master_get_devdata(spi->master); - if (!spi->max_speed_hz - || spi->max_speed_hz > c->max_speed_hz - || spi->max_speed_hz < c->min_speed_hz) + if (!spi->max_speed_hz) return -EINVAL; if (gpio_direction_output(spi->chip_select, @@ -309,15 +306,12 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) /* check each transfer's parameters */ list_for_each_entry(t, &m->transfers, transfer_list) { - u32 speed_hz = t->speed_hz ? : spi->max_speed_hz; u8 bits_per_word = t->bits_per_word; if (!t->tx_buf && !t->rx_buf && t->len) return -EINVAL; if (t->len & ((bits_per_word >> 3) - 1)) return -EINVAL; - if (speed_hz < c->min_speed_hz || speed_hz > c->max_speed_hz) - return -EINVAL; } spin_lock_irqsave(&c->lock, flags); @@ -360,8 +354,8 @@ static int txx9spi_probe(struct platform_device *dev) goto exit; } c->baseclk = clk_get_rate(c->clk); - c->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); - c->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); + master->min_speed_hz = DIV_ROUND_UP(c->baseclk, SPI_MAX_DIVIDER + 1); + master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res) From 383840d92f8e5e4c3ab4090e5d8f2ca5cf893802 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 Feb 2014 21:48:16 +0800 Subject: [PATCH 058/201] spi: tegra114: Convert to use master->max_speed_hz Use master->max_speed_hz instead of tspi->spi_max_frequency, so spi core will handle checking transfer speed. In additional, since commit 052eb2d49006 'spi: core: Set max_speed_hz of spi_device default to max_speed_hz of controller', spi core will also set default spi->max_speed_hz if it is not set. So remove the duplicate code in tegra_spi_setup. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/spi/spi-tegra114.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 413c71843492..d8c71b81165a 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -172,7 +172,6 @@ struct tegra_spi_data { void __iomem *base; phys_addr_t phys; unsigned irq; - u32 spi_max_frequency; u32 cur_speed; struct spi_device *cur_spi; @@ -763,9 +762,6 @@ static int tegra_spi_setup(struct spi_device *spi) BUG_ON(spi->chip_select >= MAX_CHIP_SELECT); - /* Set speed to the spi max fequency if spi device has not set */ - spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency; - ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); @@ -1019,16 +1015,6 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data) return IRQ_WAKE_THREAD; } -static void tegra_spi_parse_dt(struct platform_device *pdev, - struct tegra_spi_data *tspi) -{ - struct device_node *np = pdev->dev.of_node; - - if (of_property_read_u32(np, "spi-max-frequency", - &tspi->spi_max_frequency)) - tspi->spi_max_frequency = 25000000; /* 25MHz */ -} - static struct of_device_id tegra_spi_of_match[] = { { .compatible = "nvidia,tegra114-spi", }, {} @@ -1050,8 +1036,9 @@ static int tegra_spi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); tspi = spi_master_get_devdata(master); - /* Parse DT */ - tegra_spi_parse_dt(pdev, tspi); + if (of_property_read_u32(pdev->dev.of_node, "spi-max-frequency", + &master->max_speed_hz)) + master->max_speed_hz = 25000000; /* 25MHz */ /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; From 44830b4c2f978a1bc667d1557d26277a7e593cf5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 Feb 2014 21:49:49 +0800 Subject: [PATCH 059/201] spi: tegra20-sflash: Convert to use master->max_speed_hz Use master->max_speed_hz instead of tspi->spi_max_frequency, so spi core will handle checking transfer speed. In additional, since commit 052eb2d49006 'spi: core: Set max_speed_hz of spi_device default to max_speed_hz of controller', spi core will also set default spi->max_speed_hz if it is not set. So remove tegra_sflash_setup(). Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-sflash.c | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 08794977f21a..c60d5df054ee 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -121,7 +121,6 @@ struct tegra_sflash_data { struct reset_control *rst; void __iomem *base; unsigned irq; - u32 spi_max_frequency; u32 cur_speed; struct spi_device *cur_spi; @@ -315,15 +314,6 @@ static int tegra_sflash_start_transfer_one(struct spi_device *spi, return tegra_sflash_start_cpu_based_transfer(tsd, t); } -static int tegra_sflash_setup(struct spi_device *spi) -{ - struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master); - - /* Set speed to the spi max fequency if spi device has not set */ - spi->max_speed_hz = spi->max_speed_hz ? : tsd->spi_max_frequency; - return 0; -} - static int tegra_sflash_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -430,15 +420,6 @@ static irqreturn_t tegra_sflash_isr(int irq, void *context_data) return handle_cpu_based_xfer(tsd); } -static void tegra_sflash_parse_dt(struct tegra_sflash_data *tsd) -{ - struct device_node *np = tsd->dev->of_node; - - if (of_property_read_u32(np, "spi-max-frequency", - &tsd->spi_max_frequency)) - tsd->spi_max_frequency = 25000000; /* 25MHz */ -} - static struct of_device_id tegra_sflash_of_match[] = { { .compatible = "nvidia,tegra20-sflash", }, {} @@ -467,7 +448,6 @@ static int tegra_sflash_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA; - master->setup = tegra_sflash_setup; master->transfer_one_message = tegra_sflash_transfer_one_message; master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; @@ -479,7 +459,9 @@ static int tegra_sflash_probe(struct platform_device *pdev) tsd->dev = &pdev->dev; spin_lock_init(&tsd->lock); - tegra_sflash_parse_dt(tsd); + if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency", + &master->max_speed_hz)) + master->max_speed_hz = 25000000; /* 25MHz */ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); tsd->base = devm_ioremap_resource(&pdev->dev, r); From 3c604de496d7568b3fddb9f2531630aa89908186 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 Feb 2014 21:51:13 +0800 Subject: [PATCH 060/201] spi: tegra20-slink: Convert to use master->max_speed_hz Use master->max_speed_hz instead of tspi->spi_max_frequency, so spi core will handle checking transfer speed. In additional, since commit 052eb2d49006 'spi: core: Set max_speed_hz of spi_device default to max_speed_hz of controller', spi core will also set default spi->max_speed_hz if it is not set. So remove the duplicate code in tegra_slink_setup. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/spi/spi-tegra20-slink.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index be3a069879c3..9da14f2e2818 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -171,7 +171,6 @@ struct tegra_slink_data { void __iomem *base; phys_addr_t phys; unsigned irq; - u32 spi_max_frequency; u32 cur_speed; struct spi_device *cur_spi; @@ -763,8 +762,6 @@ static int tegra_slink_setup(struct spi_device *spi) BUG_ON(spi->chip_select >= MAX_CHIP_SELECT); - /* Set speed to the spi max fequency if spi device has not set */ - spi->max_speed_hz = spi->max_speed_hz ? : tspi->spi_max_frequency; ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); @@ -999,15 +996,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data) return IRQ_WAKE_THREAD; } -static void tegra_slink_parse_dt(struct tegra_slink_data *tspi) -{ - struct device_node *np = tspi->dev->of_node; - - if (of_property_read_u32(np, "spi-max-frequency", - &tspi->spi_max_frequency)) - tspi->spi_max_frequency = 25000000; /* 25MHz */ -} - static const struct tegra_slink_chip_data tegra30_spi_cdata = { .cs_hold_time = true, }; @@ -1062,7 +1050,9 @@ static int tegra_slink_probe(struct platform_device *pdev) tspi->chip_data = cdata; spin_lock_init(&tspi->lock); - tegra_slink_parse_dt(tspi); + if (of_property_read_u32(tspi->dev->of_node, "spi-max-frequency", + &master->max_speed_hz)) + master->max_speed_hz = 25000000; /* 25MHz */ r = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!r) { From c5c67e31bc1b96658169b5b553b9be42e2ca6368 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 11 Feb 2014 20:54:17 +0800 Subject: [PATCH 061/201] spi: sc18is602: Move checking chip_select for SC18IS602 to sc18is602_setup So it will be checked when spi device is added onto the spi bus. spi_add_device() calls spi_setup() which then calls spi->master->setup(). No need to check it every time sc18is602_transfer_one() is called. Signed-off-by: Axel Lin Acked-by: Guenter Roeck Signed-off-by: Mark Brown --- drivers/spi/spi-sc18is602.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index b3ac776def9b..7fba10bba3b0 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -205,12 +205,6 @@ static int sc18is602_transfer_one(struct spi_master *master, struct spi_transfer *t; int status = 0; - /* SC18IS602 does not support CS2 */ - if (hw->id == sc18is602 && spi->chip_select == 2) { - status = -ENXIO; - goto error; - } - hw->tlen = 0; list_for_each_entry(t, &m->transfers, transfer_list) { u32 hz = t->speed_hz ? : spi->max_speed_hz; @@ -238,13 +232,23 @@ static int sc18is602_transfer_one(struct spi_master *master, if (t->delay_usecs) udelay(t->delay_usecs); } -error: m->status = status; spi_finalize_current_message(master); return status; } +static int sc18is602_setup(struct spi_device *spi) +{ + struct sc18is602 *hw = spi_master_get_devdata(spi->master); + + /* SC18IS602 does not support CS2 */ + if (hw->id == sc18is602 && spi->chip_select == 2) + return -ENXIO; + + return 0; +} + static int sc18is602_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -298,6 +302,7 @@ static int sc18is602_probe(struct i2c_client *client, master->bus_num = client->adapter->nr; master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_LSB_FIRST; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->setup = sc18is602_setup; master->transfer_one_message = sc18is602_transfer_one; master->dev.of_node = np; From 495b335885f822444b66be3b81edcd4835f379c5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 11 Feb 2014 20:51:36 +0800 Subject: [PATCH 062/201] spi: orion: Convert to let spi core validate xfer->bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 20f174ee06ec..caaa53fc68cc 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -73,23 +73,6 @@ orion_spi_clrbits(struct orion_spi *orion_spi, u32 reg, u32 mask) writel(val, reg_addr); } -static int orion_spi_set_transfer_size(struct orion_spi *orion_spi, int size) -{ - if (size == 16) { - orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, - ORION_SPI_IF_8_16_BIT_MODE); - } else if (size == 8) { - orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, - ORION_SPI_IF_8_16_BIT_MODE); - } else { - pr_debug("Bad bits per word value %d (only 8 or 16 are allowed).\n", - size); - return -EINVAL; - } - - return 0; -} - static int orion_spi_baudrate_set(struct spi_device *spi, unsigned int speed) { u32 tclk_hz; @@ -168,7 +151,14 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) if (rc) return rc; - return orion_spi_set_transfer_size(orion_spi, bits_per_word); + if (bits_per_word == 16) + orion_spi_setbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + else + orion_spi_clrbits(orion_spi, ORION_SPI_IF_CONFIG_REG, + ORION_SPI_IF_8_16_BIT_MODE); + + return 0; } static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable) @@ -391,6 +381,7 @@ static int orion_spi_probe(struct platform_device *pdev) master->transfer_one_message = orion_spi_transfer_one_message; master->num_chipselect = ORION_NUM_CHIPSELECTS; + master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); platform_set_drvdata(pdev, master); From 0fd73763350fee019cd35d8d4c3c384f6ee493a1 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 8 Feb 2014 23:12:20 +0800 Subject: [PATCH 063/201] spi: octeon: Remove unused bits_per_word from struct octeon_spi_setup Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-octeon.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 862ef30853d3..31b41445a85e 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -37,7 +37,6 @@ struct octeon_spi_setup { u32 max_speed_hz; u8 chip_select; u8 mode; - u8 bits_per_word; }; static void octeon_spi_wait_ready(struct octeon_spi *p) @@ -204,7 +203,6 @@ static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi) setup->max_speed_hz = spi->max_speed_hz; setup->chip_select = spi->chip_select; setup->mode = spi->mode; - setup->bits_per_word = spi->bits_per_word; return setup; } From 354312f16e49add1da78f0cfb2bcb633709d0071 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 11 Feb 2014 22:07:30 +0800 Subject: [PATCH 064/201] spi: Remove duplicate code to check chip_select In spi_add_device(), we have the code to validate spi->chip_select. So remove the duplicate code in various drivers. Signed-off-by: Axel Lin Acked-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 7 ------- drivers/spi/spi-coldfire-qspi.c | 6 ------ drivers/spi/spi-falcon.c | 3 --- drivers/spi/spi-mpc52xx.c | 3 --- drivers/spi/spi-omap-uwire.c | 6 ------ drivers/spi/spi-tegra114.c | 2 -- drivers/spi/spi-tegra20-slink.c | 2 -- 7 files changed, 29 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index b0842f751016..5488ab86312f 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -993,13 +993,6 @@ static int atmel_spi_setup(struct spi_device *spi) as = spi_master_get_devdata(spi->master); - if (spi->chip_select > spi->master->num_chipselect) { - dev_dbg(&spi->dev, - "setup: invalid chipselect %u (%u defined)\n", - spi->chip_select, spi->master->num_chipselect); - return -EINVAL; - } - /* see notes above re chipselect */ if (!atmel_spi_is_v2(as) && spi->chip_select == 0 diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index cabed8f9119e..0ab2c55575dd 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -356,12 +356,6 @@ static int mcfqspi_transfer_one_message(struct spi_master *master, static int mcfqspi_setup(struct spi_device *spi) { - if (spi->chip_select >= spi->master->num_chipselect) { - dev_dbg(&spi->dev, "%d chip select is out of range\n", - spi->chip_select); - return -EINVAL; - } - mcfqspi_cs_deselect(spi_master_get_devdata(spi->master), spi->chip_select, spi->mode & SPI_CS_HIGH); diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index dd5bd468e962..0ae7f45e24a5 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -312,9 +312,6 @@ static int falcon_sflash_setup(struct spi_device *spi) unsigned int i; unsigned long flags; - if (spi->chip_select > 0) - return -ENODEV; - spin_lock_irqsave(&ebu_lock, flags); if (spi->max_speed_hz >= CLOCK_100M) { diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index 7c675fe83101..e3d29a56d70a 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -365,9 +365,6 @@ static int mpc52xx_spi_setup(struct spi_device *spi) if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) return -EINVAL; - if (spi->chip_select >= spi->master->num_chipselect) - return -EINVAL; - return 0; } diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 9313fd3b413d..462ddd458217 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -332,12 +332,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) uwire = spi_master_get_devdata(spi->master); - if (spi->chip_select > 3) { - pr_debug("%s: cs%d?\n", dev_name(&spi->dev), spi->chip_select); - status = -ENODEV; - goto done; - } - bits = spi->bits_per_word; if (t != NULL && t->bits_per_word) bits = t->bits_per_word; diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index d8c71b81165a..22905b5d2546 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -760,8 +760,6 @@ static int tegra_spi_setup(struct spi_device *spi) spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); - BUG_ON(spi->chip_select >= MAX_CHIP_SELECT); - ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 9da14f2e2818..593e823d6c21 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -760,8 +760,6 @@ static int tegra_slink_setup(struct spi_device *spi) spi->mode & SPI_CPHA ? "" : "~", spi->max_speed_hz); - BUG_ON(spi->chip_select >= MAX_CHIP_SELECT); - ret = pm_runtime_get_sync(tspi->dev); if (ret < 0) { dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret); From 513273538a6c10dba1170ecdee5c2da15acecdb5 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 12 Feb 2014 20:31:26 +0000 Subject: [PATCH 065/201] spi: Make max_tx and max_rx the same type Prevents spurious compiler warnings. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 49313dd0a144..f3fb1acf9ac1 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -644,7 +644,7 @@ static int spi_map_msg(struct spi_master *master, struct spi_message *msg) struct device *tx_dev, *rx_dev; struct spi_transfer *xfer; void *tmp; - size_t max_tx, max_rx; + unsigned int max_tx, max_rx; int ret; if (master->flags & (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX)) { From aec35f4ee6eefba616065547e6882c084cc7f5cb Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Thu, 13 Feb 2014 15:28:41 +0100 Subject: [PATCH 066/201] spi: Clean up probe and remove functions While backporting 33cf00e5 ("spi: attach/detach SPI device to the ACPI power domain"), I noticed that the code changes were suboptimal: * Why use &spi->dev when we have dev at hand? * After fixing the above, spi is used only once, so we don't really need a local variable for it. This results in the following clean-up. Signed-off-by: Jean Delvare Acked-by: Rafael J. Wysocki Signed-off-by: Mark Brown --- drivers/spi/spi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 23756b0f9036..bb660145d19e 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -255,13 +255,12 @@ EXPORT_SYMBOL_GPL(spi_bus_type); static int spi_drv_probe(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); - struct spi_device *spi = to_spi_device(dev); int ret; - acpi_dev_pm_attach(&spi->dev, true); - ret = sdrv->probe(spi); + acpi_dev_pm_attach(dev, true); + ret = sdrv->probe(to_spi_device(dev)); if (ret) - acpi_dev_pm_detach(&spi->dev, true); + acpi_dev_pm_detach(dev, true); return ret; } @@ -269,11 +268,10 @@ static int spi_drv_probe(struct device *dev) static int spi_drv_remove(struct device *dev) { const struct spi_driver *sdrv = to_spi_driver(dev->driver); - struct spi_device *spi = to_spi_device(dev); int ret; - ret = sdrv->remove(spi); - acpi_dev_pm_detach(&spi->dev, true); + ret = sdrv->remove(to_spi_device(dev)); + acpi_dev_pm_detach(dev, true); return ret; } From 08850fa94831d374f4d827a85088f6087836dfc8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Feb 2014 20:38:16 +0800 Subject: [PATCH 067/201] spi: s3c24xx: Convert to let spi core validate bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 746424aa5353..f1ffbfa6acef 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -123,25 +123,15 @@ static int s3c24xx_spi_update_state(struct spi_device *spi, { struct s3c24xx_spi *hw = to_hw(spi); struct s3c24xx_spi_devstate *cs = spi->controller_state; - unsigned int bpw; unsigned int hz; unsigned int div; unsigned long clk; - bpw = t ? t->bits_per_word : spi->bits_per_word; hz = t ? t->speed_hz : spi->max_speed_hz; - if (!bpw) - bpw = 8; - if (!hz) hz = spi->max_speed_hz; - if (bpw != 8) { - dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw); - return -EINVAL; - } - if (spi->mode != cs->mode) { u8 spcon = SPCON_DEFAULT | S3C2410_SPCON_ENSCK; @@ -544,6 +534,7 @@ static int s3c24xx_spi_probe(struct platform_device *pdev) master->num_chipselect = hw->pdata->num_cs; master->bus_num = pdata->bus_num; + master->bits_per_word_mask = SPI_BPW_MASK(8); /* setup the state for the bitbang driver */ From 54457fa5bae5e84e2b63d52a7b2d520e7a60f8b8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 3 Feb 2014 10:51:30 +0800 Subject: [PATCH 068/201] spi: bfin5xx: Remove duplicate code to check spi->mode This checking is already done in the implementation of spi_setup(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-bfin5xx.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index f0f195af75d4..c6902d2087d2 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -1030,10 +1030,6 @@ static int bfin_spi_setup(struct spi_device *spi) } /* translate common spi framework into our register */ - if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) { - dev_err(&spi->dev, "unsupported spi modes detected\n"); - goto error; - } if (spi->mode & SPI_CPOL) chip->ctl_reg |= BIT_CTL_CPOL; if (spi->mode & SPI_CPHA) From 8120ff8c48396a75cc9e5fa26a7a476479003fab Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 8 Feb 2014 11:15:57 +0800 Subject: [PATCH 069/201] spi: nuc900: Remove unused fields from struct nuc900_spi Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-nuc900.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 50406306bc20..6d36c35c86f5 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -58,11 +58,8 @@ struct nuc900_spi { unsigned char *rx; struct clk *clk; struct spi_master *master; - struct spi_device *curdev; - struct device *dev; struct nuc900_spi_info *pdata; spinlock_t lock; - struct resource *res; }; static inline struct nuc900_spi *to_hw(struct spi_device *sdev) @@ -338,6 +335,7 @@ static int nuc900_spi_probe(struct platform_device *pdev) { struct nuc900_spi *hw; struct spi_master *master; + struct resource *res; int err = 0; master = spi_alloc_master(&pdev->dev, sizeof(struct nuc900_spi)); @@ -349,7 +347,6 @@ static int nuc900_spi_probe(struct platform_device *pdev) hw = spi_master_get_devdata(master); hw->master = master; hw->pdata = dev_get_platdata(&pdev->dev); - hw->dev = &pdev->dev; if (hw->pdata == NULL) { dev_err(&pdev->dev, "No platform data supplied\n"); @@ -367,8 +364,8 @@ static int nuc900_spi_probe(struct platform_device *pdev) hw->bitbang.chipselect = nuc900_spi_chipsel; hw->bitbang.txrx_bufs = nuc900_spi_txrx; - hw->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hw->regs = devm_ioremap_resource(&pdev->dev, hw->res); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hw->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(hw->regs)) { err = PTR_ERR(hw->regs); goto err_pdata; From 56fc0b42dc5aeb4ee2b10ab5785e28c87c83280a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 8 Feb 2014 23:52:26 +0800 Subject: [PATCH 070/201] spi: ep93xx: Convert to let spi core handle checking transfer speed By setting master->max_speed_hz and master->min_speed_hz, spi core will handle checking transfer speed. So we can remove the same checking in this driver. Signed-off-by: Axel Lin Acked-by: Mika Westerberg Signed-off-by: Mark Brown --- drivers/spi/spi-ep93xx.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index 1bfaed6e4073..2f675d32df0e 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -73,8 +73,6 @@ * @clk: clock for the controller * @regs_base: pointer to ioremap()'d registers * @sspdr_phys: physical address of the SSPDR register - * @min_rate: minimum clock rate (in Hz) supported by the controller - * @max_rate: maximum clock rate (in Hz) supported by the controller * @wait: wait here until given transfer is completed * @current_msg: message that is currently processed (or %NULL if none) * @tx: current byte in transfer to transmit @@ -95,8 +93,6 @@ struct ep93xx_spi { struct clk *clk; void __iomem *regs_base; unsigned long sspdr_phys; - unsigned long min_rate; - unsigned long max_rate; struct completion wait; struct spi_message *current_msg; size_t tx; @@ -199,9 +195,9 @@ static void ep93xx_spi_disable_interrupts(const struct ep93xx_spi *espi) * @div_scr: pointer to return the scr divider */ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, - unsigned long rate, - u8 *div_cpsr, u8 *div_scr) + u32 rate, u8 *div_cpsr, u8 *div_scr) { + struct spi_master *master = platform_get_drvdata(espi->pdev); unsigned long spi_clk_rate = clk_get_rate(espi->clk); int cpsr, scr; @@ -210,7 +206,7 @@ static int ep93xx_spi_calc_divisors(const struct ep93xx_spi *espi, * controller. Note that minimum value is already checked in * ep93xx_spi_transfer_one_message(). */ - rate = clamp(rate, espi->min_rate, espi->max_rate); + rate = clamp(rate, master->min_speed_hz, master->max_speed_hz); /* * Calculate divisors so that we can get speed according the @@ -735,13 +731,6 @@ static int ep93xx_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { struct ep93xx_spi *espi = spi_master_get_devdata(master); - struct spi_transfer *t; - - /* first validate each transfer */ - list_for_each_entry(t, &msg->transfers, transfer_list) { - if (t->speed_hz < espi->min_rate) - return -EINVAL; - } msg->state = NULL; msg->status = 0; @@ -917,8 +906,8 @@ static int ep93xx_spi_probe(struct platform_device *pdev) * Calculate maximum and minimum supported clock rates * for the controller. */ - espi->max_rate = clk_get_rate(espi->clk) / 2; - espi->min_rate = clk_get_rate(espi->clk) / (254 * 256); + master->max_speed_hz = clk_get_rate(espi->clk) / 2; + master->min_speed_hz = clk_get_rate(espi->clk) / (254 * 256); espi->pdev = pdev; espi->sspdr_phys = res->start + SSPDR; From 6e3bc2b7b39e565f61665ae84f41e5ccb791992b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 9 Feb 2014 11:25:34 +0800 Subject: [PATCH 071/201] spi: bfin5xx: Remove unused last_transfer pointer in bfin_spi_giveback() Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-bfin5xx.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/spi/spi-bfin5xx.c b/drivers/spi/spi-bfin5xx.c index c6902d2087d2..55e57c3eb9bd 100644 --- a/drivers/spi/spi-bfin5xx.c +++ b/drivers/spi/spi-bfin5xx.c @@ -350,7 +350,6 @@ static void *bfin_spi_next_transfer(struct bfin_spi_master_data *drv_data) static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) { struct bfin_spi_slave_data *chip = drv_data->cur_chip; - struct spi_transfer *last_transfer; unsigned long flags; struct spi_message *msg; @@ -362,9 +361,6 @@ static void bfin_spi_giveback(struct bfin_spi_master_data *drv_data) queue_work(drv_data->workqueue, &drv_data->pump_messages); spin_unlock_irqrestore(&drv_data->lock, flags); - last_transfer = list_entry(msg->transfers.prev, - struct spi_transfer, transfer_list); - msg->state = NULL; if (!drv_data->cs_change) From fe3a1ad0c60d7ac405f52b5c76ef45c22e054d0c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 10 Feb 2014 22:26:40 +0800 Subject: [PATCH 072/201] spi: topcliff-pch: Convert to use master->max_speed_hz Set "master->max_speed_hz = PCH_MAX_BAUDRATE" then we can remove pch_spi_setup. In additional, pspi->max_speed_hz will never be 0 because it's default value will be set to master->max_speed_hz. Also remove list_empty checking in pch_spi_transfer() because the checking is done by spi core. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 37 +--------------------------------- 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 2e7f38c7a961..6304c91e6965 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -464,20 +464,6 @@ static void pch_spi_reset(struct spi_master *master) pch_spi_writereg(master, PCH_SRST, 0x0); } -static int pch_spi_setup(struct spi_device *pspi) -{ - /* Check baud rate setting */ - /* if baud rate of chip is greater than - max we can support,return error */ - if ((pspi->max_speed_hz) > PCH_MAX_BAUDRATE) - pspi->max_speed_hz = PCH_MAX_BAUDRATE; - - dev_dbg(&pspi->dev, "%s MODE = %x\n", __func__, - (pspi->mode) & (SPI_CPOL | SPI_CPHA)); - - return 0; -} - static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) { @@ -486,23 +472,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) int retval; unsigned long flags; - /* validate spi message and baud rate */ - if (unlikely(list_empty(&pmsg->transfers) == 1)) { - dev_err(&pspi->dev, "%s list empty\n", __func__); - retval = -EINVAL; - goto err_out; - } - - if (unlikely(pspi->max_speed_hz == 0)) { - dev_err(&pspi->dev, "%s pch_spi_transfer maxspeed=%d\n", - __func__, pspi->max_speed_hz); - retval = -EINVAL; - goto err_out; - } - - dev_dbg(&pspi->dev, - "%s Transfer List not empty. Transfer Speed is set.\n", __func__); - spin_lock_irqsave(&data->lock, flags); /* validate Tx/Rx buffers and Transfer length */ list_for_each_entry(transfer, &pmsg->transfers, transfer_list) { @@ -523,10 +492,6 @@ static int pch_spi_transfer(struct spi_device *pspi, struct spi_message *pmsg) dev_dbg(&pspi->dev, "%s Tx/Rx buffer valid. Transfer length valid\n", __func__); - - /* if baud rate has been specified validate the same */ - if (transfer->speed_hz > PCH_MAX_BAUDRATE) - transfer->speed_hz = PCH_MAX_BAUDRATE; } spin_unlock_irqrestore(&data->lock, flags); @@ -1418,10 +1383,10 @@ static int pch_spi_pd_probe(struct platform_device *plat_dev) /* initialize members of SPI master */ master->num_chipselect = PCH_MAX_CS; - master->setup = pch_spi_setup; master->transfer = pch_spi_transfer; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + master->max_speed_hz = PCH_MAX_BAUDRATE; data->board_dat = board_dat; data->plat_dev = plat_dev; From 0dd26e53b56137431e373c781fe2984393c9d573 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 11 Feb 2014 20:49:07 +0800 Subject: [PATCH 073/201] spi: au1550: Convert to let spi core handle checking transfer speed By setting master->max_speed_hz and master->min_speed_hz, spi core will handle checking transfer speed. So we can remove the same checking in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-au1550.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c index c4141c92bcff..aafb812d7ea6 100644 --- a/drivers/spi/spi-au1550.c +++ b/drivers/spi/spi-au1550.c @@ -55,8 +55,6 @@ struct au1550_spi { volatile psc_spi_t __iomem *regs; int irq; - unsigned freq_max; - unsigned freq_min; unsigned len; unsigned tx_count; @@ -248,11 +246,8 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) hz = t->speed_hz; } - if (hz > spi->max_speed_hz || hz > hw->freq_max || hz < hw->freq_min) { - dev_err(&spi->dev, "setupxfer: clock rate=%d out of range\n", - hz); + if (!hz) return -EINVAL; - } au1550_spi_bits_handlers_set(hw, spi->bits_per_word); @@ -287,23 +282,6 @@ static int au1550_spi_setupxfer(struct spi_device *spi, struct spi_transfer *t) return 0; } -static int au1550_spi_setup(struct spi_device *spi) -{ - struct au1550_spi *hw = spi_master_get_devdata(spi->master); - - if (spi->max_speed_hz == 0) - spi->max_speed_hz = hw->freq_max; - if (spi->max_speed_hz > hw->freq_max - || spi->max_speed_hz < hw->freq_min) - return -EINVAL; - /* - * NOTE: cannot change speed and other hw settings immediately, - * otherwise sharing of spi bus is not possible, - * so do not call setupxfer(spi, NULL) here - */ - return 0; -} - /* * for dma spi transfers, we have to setup rx channel, otherwise there is * no reliable way how to recognize that spi transfer is done @@ -838,7 +816,6 @@ static int au1550_spi_probe(struct platform_device *pdev) hw->bitbang.master = hw->master; hw->bitbang.setup_transfer = au1550_spi_setupxfer; hw->bitbang.chipselect = au1550_spi_chipsel; - hw->bitbang.master->setup = au1550_spi_setup; hw->bitbang.txrx_bufs = au1550_spi_txrx_bufs; if (hw->usedma) { @@ -909,8 +886,9 @@ static int au1550_spi_probe(struct platform_device *pdev) { int min_div = (2 << 0) * (2 * (4 + 1)); int max_div = (2 << 3) * (2 * (63 + 1)); - hw->freq_max = hw->pdata->mainclk_hz / min_div; - hw->freq_min = hw->pdata->mainclk_hz / (max_div + 1) + 1; + master->max_speed_hz = hw->pdata->mainclk_hz / min_div; + master->min_speed_hz = + hw->pdata->mainclk_hz / (max_div + 1) + 1; } au1550_spi_setup_psc_as_spi(hw); From cdd1945bde1e03149899a5d65c54fc0f163d24ac Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 14 Feb 2014 01:19:21 -0200 Subject: [PATCH 074/201] spi: spi-mxs: Propagate the real error code on platform_get_irq() failure No need to return a 'fake' return value on platform_get_irq() failure. Just return the error code itself instead. Signed-off-by: Fabio Estevam Acked-by: Marek Vasut Signed-off-by: Mark Brown --- drivers/spi/spi-mxs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c index d3803198e166..5bf807a466e3 100644 --- a/drivers/spi/spi-mxs.c +++ b/drivers/spi/spi-mxs.c @@ -473,7 +473,7 @@ static int mxs_spi_probe(struct platform_device *pdev) iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq_err = platform_get_irq(pdev, 0); if (irq_err < 0) - return -EINVAL; + return irq_err; base = devm_ioremap_resource(&pdev->dev, iores); if (IS_ERR(base)) From 82106e0e39c455957888dd44d43790306b30f73e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 14 Feb 2014 01:19:22 -0200 Subject: [PATCH 075/201] spi: spi-imx: Propagate the real error code on platform_get_irq() failure No need to return a 'fake' return value on platform_get_irq() failure. Just return the error code itself instead. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index a5474ef9d2a0..ad6daf510d33 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -880,7 +880,7 @@ static int spi_imx_probe(struct platform_device *pdev) spi_imx->irq = platform_get_irq(pdev, 0); if (spi_imx->irq < 0) { - ret = -EINVAL; + ret = spi_imx->irq; goto out_master_put; } From d31ad46f58e89fdb9f5b902aa7cc29689e123dde Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 13 Feb 2014 10:18:15 +0800 Subject: [PATCH 076/201] spi: sun6i: Fix define for SUN6I_TFR_CTL_CS_MASK Current code in sun6i_spi_set_cs() actually clears CPHA and CPOL bits which is obvious wrong. The define for SUN6I_TFR_CTL_CS_MASK is wrong. Fix it. Signed-off-by: Axel Lin Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 94d38d0a86cd..4b9ec08022fe 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -36,8 +36,8 @@ #define SUN6I_TFR_CTL_CPHA BIT(0) #define SUN6I_TFR_CTL_CPOL BIT(1) #define SUN6I_TFR_CTL_SPOL BIT(2) -#define SUN6I_TFR_CTL_CS_MASK 0x3 -#define SUN6I_TFR_CTL_CS(cs) (((cs) & SUN6I_TFR_CTL_CS_MASK) << 4) +#define SUN6I_TFR_CTL_CS_MASK 0x30 +#define SUN6I_TFR_CTL_CS(cs) (((cs) << 4) & SUN6I_TFR_CTL_CS_MASK) #define SUN6I_TFR_CTL_CS_MANUAL BIT(6) #define SUN6I_TFR_CTL_CS_LEVEL BIT(7) #define SUN6I_TFR_CTL_DHB BIT(8) From 1acbdeb92c87fc18eade0815dedc257fe45b88b7 Mon Sep 17 00:00:00 2001 From: Chao Fu Date: Wed, 12 Feb 2014 15:29:05 +0800 Subject: [PATCH 077/201] spi/fsl-dspi: Convert to use regmap and add big-endian support Freescale DSPI module will have two endianess in different platform, but ARM is little endian. So when DSPI in big endian, core in little endian, readl and writel can not adjust R/W register in this condition. This patch will remove general readl/writel, and import regmap mechanism. Data endian will be transfered in regmap APIs. Documents: dspi add bool "big-endian" in dts node if DSPI module work in big endian. Signed-off-by: Chao Fu Reviewed-by: Xiubo Li Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-fsl-dspi.txt | 2 + drivers/spi/Kconfig | 1 + drivers/spi/spi-fsl-dspi.c | 80 ++++++++++++------- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt index a1fb3035a42b..5376de40f10b 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt @@ -10,6 +10,7 @@ Required properties: - pinctrl-names: must contain a "default" entry. - spi-num-chipselects : the number of the chipselect signals. - bus-num : the slave chip chipselect signal number. +- big-endian : if DSPI modudle is big endian, the bool will be set in node. Example: dspi0@4002c000 { @@ -24,6 +25,7 @@ dspi0@4002c000 { bus-num = <0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_dspi0_1>; + big-endian; status = "okay"; sflash: at26df081a@0 { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..00e951045aac 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -270,6 +270,7 @@ config SPI_FSL_SPI config SPI_FSL_DSPI tristate "Freescale DSPI controller" select SPI_BITBANG + select REGMAP_MMIO depends on SOC_VF610 || COMPILE_TEST help This enables support for the Freescale DSPI controller in master diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index ec79f726672a..fb16575d233f 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -108,7 +109,7 @@ struct fsl_dspi { struct spi_bitbang bitbang; struct platform_device *pdev; - void __iomem *base; + struct regmap *regmap; int irq; struct clk *clk; @@ -129,18 +130,11 @@ struct fsl_dspi { static inline int is_double_byte_mode(struct fsl_dspi *dspi) { - return ((readl(dspi->base + SPI_CTAR(dspi->cs)) & SPI_FRAME_BITS_MASK) - == SPI_FRAME_BITS(8)) ? 0 : 1; -} + unsigned int val; -static void set_bit_mode(struct fsl_dspi *dspi, unsigned char bits) -{ - u32 temp; + regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val); - temp = readl(dspi->base + SPI_CTAR(dspi->cs)); - temp &= ~SPI_FRAME_BITS_MASK; - temp |= SPI_FRAME_BITS(bits); - writel(temp, dspi->base + SPI_CTAR(dspi->cs)); + return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1; } static void hz_to_spi_baud(char *pbr, char *br, int speed_hz, @@ -188,7 +182,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) */ if (tx_word && (dspi->len == 1)) { dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM; - set_bit_mode(dspi, 8); + regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); tx_word = 0; } @@ -238,7 +233,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) dspi_pushr |= SPI_PUSHR_CTCNT; /* clear counter */ } - writel(dspi_pushr, dspi->base + SPI_PUSHR); + regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr); + tx_count++; } @@ -253,17 +249,23 @@ static int dspi_transfer_read(struct fsl_dspi *dspi) while ((dspi->rx < dspi->rx_end) && (rx_count < DSPI_FIFO_SIZE)) { if (rx_word) { + unsigned int val; + if ((dspi->rx_end - dspi->rx) == 1) break; - d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); + regmap_read(dspi->regmap, SPI_POPR, &val); + d = SPI_POPR_RXDATA(val); if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) *(u16 *)dspi->rx = d; dspi->rx += 2; } else { - d = SPI_POPR_RXDATA(readl(dspi->base + SPI_POPR)); + unsigned int val; + + regmap_read(dspi->regmap, SPI_POPR, &val); + d = SPI_POPR_RXDATA(val); if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) *(u8 *)dspi->rx = d; dspi->rx++; @@ -295,13 +297,13 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t) if (!dspi->tx) dspi->dataflags |= TRAN_STATE_TX_VOID; - writel(dspi->cur_chip->mcr_val, dspi->base + SPI_MCR); - writel(dspi->cur_chip->ctar_val, dspi->base + SPI_CTAR(dspi->cs)); - writel(SPI_RSER_EOQFE, dspi->base + SPI_RSER); + regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val); + regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val); + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); if (t->speed_hz) - writel(dspi->cur_chip->ctar_val, - dspi->base + SPI_CTAR(dspi->cs)); + regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), + dspi->cur_chip->ctar_val); dspi_transfer_write(dspi); @@ -315,7 +317,9 @@ static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t) static void dspi_chipselect(struct spi_device *spi, int value) { struct fsl_dspi *dspi = spi_master_get_devdata(spi->master); - u32 pushr = readl(dspi->base + SPI_PUSHR); + unsigned int pushr; + + regmap_read(dspi->regmap, SPI_PUSHR, &pushr); switch (value) { case BITBANG_CS_ACTIVE: @@ -326,7 +330,7 @@ static void dspi_chipselect(struct spi_device *spi, int value) break; } - writel(pushr, dspi->base + SPI_PUSHR); + regmap_write(dspi->regmap, SPI_PUSHR, pushr); } static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) @@ -382,13 +386,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) { struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; - writel(SPI_SR_EOQF, dspi->base + SPI_SR); + regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); dspi_transfer_read(dspi); if (!dspi->len) { if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) - set_bit_mode(dspi, 16); + regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs), + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16)); + dspi->waitflags = 1; wake_up_interruptible(&dspi->waitq); } else { @@ -435,12 +441,20 @@ static const struct dev_pm_ops dspi_pm = { SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume) }; +static struct regmap_config dspi_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = 0x88, +}; + static int dspi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct spi_master *master; struct fsl_dspi *dspi; struct resource *res; + void __iomem *base; int ret = 0, cs_num, bus_num; master = spi_alloc_master(&pdev->dev, sizeof(struct fsl_dspi)); @@ -475,12 +489,24 @@ static int dspi_probe(struct platform_device *pdev) master->bus_num = bus_num; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dspi->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(dspi->base)) { - ret = PTR_ERR(dspi->base); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); goto out_master_put; } + dspi_regmap_config.lock_arg = dspi; + dspi_regmap_config.val_format_endian = + of_property_read_bool(np, "big-endian") + ? REGMAP_ENDIAN_BIG : REGMAP_ENDIAN_DEFAULT; + dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base, + &dspi_regmap_config); + if (IS_ERR(dspi->regmap)) { + dev_err(&pdev->dev, "failed to init regmap: %ld\n", + PTR_ERR(dspi->regmap)); + return PTR_ERR(dspi->regmap); + } + dspi->irq = platform_get_irq(pdev, 0); if (dspi->irq < 0) { dev_err(&pdev->dev, "can't get platform irq\n"); From 88386e858bbb21eb05c15c040dbb3e6ad1cb3568 Mon Sep 17 00:00:00 2001 From: Chao Fu Date: Wed, 12 Feb 2014 15:29:06 +0800 Subject: [PATCH 078/201] spi/fsl-dspi: Remove some coding sytle not in standard Remove some coding sytle not in standard in former code. Signed-off-by: Chao Fu Reviewed-by: Xiubo Li Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index fb16575d233f..42ede0d796a7 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -111,9 +111,9 @@ struct fsl_dspi { struct regmap *regmap; int irq; - struct clk *clk; + struct clk *clk; - struct spi_transfer *cur_transfer; + struct spi_transfer *cur_transfer; struct chip_data *cur_chip; size_t len; void *tx; @@ -124,8 +124,8 @@ struct fsl_dspi { u8 cs; u16 void_write_data; - wait_queue_head_t waitq; - u32 waitflags; + wait_queue_head_t waitq; + u32 waitflags; }; static inline int is_double_byte_mode(struct fsl_dspi *dspi) From 78e39523b8c9721250b54b7fd930aeced56cf511 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 11 Feb 2014 22:10:19 +0800 Subject: [PATCH 079/201] spi: Remove explictly set bus_num and num_chipselect to default setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The purpose of commit 1e8a52e18cfb "spi: By default setup spi_masters with 1 chipselect and dynamics bus number" is to avoid setting default value for bus_num and num_chipselect in spi master drivers. So let's remove the duplicate code. Signed-off-by: Axel Lin Acked-by: Uwe Kleine-König Acked-By: David Daney Acked-by: Stephen Warren Signed-off-by: Mark Brown --- drivers/spi/spi-bcm2835.c | 1 - drivers/spi/spi-efm32.c | 4 ---- drivers/spi/spi-falcon.c | 2 -- drivers/spi/spi-octeon.c | 2 -- drivers/spi/spi-sh-hspi.c | 1 - drivers/spi/spi-tegra114.c | 1 - drivers/spi/spi-tegra20-sflash.c | 1 - drivers/spi/spi-tegra20-slink.c | 1 - drivers/spi/spi-ti-qspi.c | 1 - 9 files changed, 14 deletions(-) diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c index 8a89dd1f2654..69167456ec1e 100644 --- a/drivers/spi/spi-bcm2835.c +++ b/drivers/spi/spi-bcm2835.c @@ -315,7 +315,6 @@ static int bcm2835_spi_probe(struct platform_device *pdev) master->mode_bits = BCM2835_SPI_MODE_BITS; master->bits_per_word_mask = SPI_BPW_MASK(8); - master->bus_num = -1; master->num_chipselect = 3; master->transfer_one_message = bcm2835_spi_transfer_one; master->dev.of_node = pdev->dev.of_node; diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index d4d3cc534792..7199d2fd2b0b 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -308,10 +308,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev, } ddata->pdata.location = location; - - /* spi core takes care about the bus number using an alias */ - master->bus_num = -1; - return 0; } diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c index dd5bd468e962..ccd257b6e2a8 100644 --- a/drivers/spi/spi-falcon.c +++ b/drivers/spi/spi-falcon.c @@ -422,9 +422,7 @@ static int falcon_sflash_probe(struct platform_device *pdev) priv->master = master; master->mode_bits = SPI_MODE_3; - master->num_chipselect = 1; master->flags = SPI_MASTER_HALF_DUPLEX; - master->bus_num = -1; master->setup = falcon_sflash_setup; master->prepare_transfer_hardware = falcon_sflash_prepare_xfer; master->transfer_one_message = falcon_sflash_xfer_one; diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 67249a48b391..e31f6d833951 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -257,8 +257,6 @@ static int octeon_spi_probe(struct platform_device *pdev) p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, resource_size(res_mem)); - /* Dynamic bus numbering */ - master->bus_num = -1; master->num_chipselect = 4; master->mode_bits = SPI_CPHA | SPI_CPOL | diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 82d2f922ffa0..755d7cc9e72f 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -298,7 +298,6 @@ static int hspi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - master->num_chipselect = 1; master->bus_num = pdev->id; master->setup = hspi_setup; master->cleanup = hspi_cleanup; diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 413c71843492..1e399ad3cc49 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -1058,7 +1058,6 @@ static int tegra_spi_probe(struct platform_device *pdev) master->setup = tegra_spi_setup; master->transfer_one_message = tegra_spi_transfer_one_message; master->num_chipselect = MAX_CHIP_SELECT; - master->bus_num = -1; master->auto_runtime_pm = true; tspi->master = master; diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 08794977f21a..44e00dba1e79 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -471,7 +471,6 @@ static int tegra_sflash_probe(struct platform_device *pdev) master->transfer_one_message = tegra_sflash_transfer_one_message; master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; - master->bus_num = -1; platform_set_drvdata(pdev, master); tsd = spi_master_get_devdata(master); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index be3a069879c3..b06ea31c1699 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1053,7 +1053,6 @@ static int tegra_slink_probe(struct platform_device *pdev) master->unprepare_message = tegra_slink_unprepare_message; master->auto_runtime_pm = true; master->num_chipselect = MAX_CHIP_SELECT; - master->bus_num = -1; platform_set_drvdata(pdev, master); tspi = spi_master_get_devdata(master); diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 3d09265b5133..de9920e9d3f8 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -429,7 +429,6 @@ static int ti_qspi_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; - master->bus_num = -1; master->flags = SPI_MASTER_HALF_DUPLEX; master->setup = ti_qspi_setup; master->auto_runtime_pm = true; From 963eb4b87dcfc0f9a1ac0ea85ca92832e61544ad Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Fri, 14 Feb 2014 12:26:17 +0530 Subject: [PATCH 080/201] spi/s3c64xx: Trivial cleanup in header file Commit 436d42c61c3e ("ARM: samsung: move platform_data definitions") moved the files to the current location but forgot to remove the pointer to its previous location. Clean it up. While at it also change the header file protection macros appropriately. Signed-off-by: Sachin Kamat Signed-off-by: Mark Brown --- include/linux/platform_data/spi-s3c64xx.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/include/linux/platform_data/spi-s3c64xx.h b/include/linux/platform_data/spi-s3c64xx.h index 8447f634c7f5..d3889b98a1a1 100644 --- a/include/linux/platform_data/spi-s3c64xx.h +++ b/include/linux/platform_data/spi-s3c64xx.h @@ -1,5 +1,4 @@ -/* linux/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h - * +/* * Copyright (C) 2009 Samsung Electronics Ltd. * Jaswinder Singh * @@ -8,8 +7,8 @@ * published by the Free Software Foundation. */ -#ifndef __S3C64XX_PLAT_SPI_H -#define __S3C64XX_PLAT_SPI_H +#ifndef __SPI_S3C64XX_H +#define __SPI_S3C64XX_H #include @@ -68,4 +67,4 @@ extern int s3c64xx_spi2_cfg_gpio(void); extern struct s3c64xx_spi_info s3c64xx_spi0_pdata; extern struct s3c64xx_spi_info s3c64xx_spi1_pdata; extern struct s3c64xx_spi_info s3c64xx_spi2_pdata; -#endif /* __S3C64XX_PLAT_SPI_H */ +#endif /*__SPI_S3C64XX_H */ From 3d8c869796b61f2dd7c1b84112902e199936c053 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 16 Feb 2014 10:43:18 +0800 Subject: [PATCH 081/201] spi: mpc512x-psc: Remove redundant code to get bus_num from DT For DT case, spi core will call of_alias_get_id() and set master->bus_num if it was not set. Signed-off-by: Axel Lin Tested-by: Gerhard Sittig Signed-off-by: Mark Brown --- drivers/spi/spi-mpc512x-psc.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/spi/spi-mpc512x-psc.c b/drivers/spi/spi-mpc512x-psc.c index 5032141eeeec..46cdfd2ac0fa 100644 --- a/drivers/spi/spi-mpc512x-psc.c +++ b/drivers/spi/spi-mpc512x-psc.c @@ -466,10 +466,8 @@ static void mpc512x_spi_cs_control(struct spi_device *spi, bool onoff) gpio_set_value(spi->cs_gpio, onoff); } -/* bus_num is used only for the case dev->platform_data == NULL */ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, - u32 size, unsigned int irq, - s16 bus_num) + u32 size, unsigned int irq) { struct fsl_spi_platform_data *pdata = dev_get_platdata(dev); struct mpc512x_psc_spi *mps; @@ -488,7 +486,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr, if (pdata == NULL) { mps->cs_control = mpc512x_spi_cs_control; - master->bus_num = bus_num; } else { mps->cs_control = pdata->cs_control; master->bus_num = pdata->bus_num; @@ -574,7 +571,6 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op) { const u32 *regaddr_p; u64 regaddr64, size64; - s16 id = -1; regaddr_p = of_get_address(op->dev.of_node, 0, &size64, NULL); if (!regaddr_p) { @@ -583,16 +579,8 @@ static int mpc512x_psc_spi_of_probe(struct platform_device *op) } regaddr64 = of_translate_address(op->dev.of_node, regaddr_p); - /* get PSC id (0..11, used by port_config) */ - id = of_alias_get_id(op->dev.of_node, "spi"); - if (id < 0) { - dev_err(&op->dev, "no alias id for %s\n", - op->dev.of_node->full_name); - return id; - } - return mpc512x_psc_spi_do_probe(&op->dev, (u32) regaddr64, (u32) size64, - irq_of_parse_and_map(op->dev.of_node, 0), id); + irq_of_parse_and_map(op->dev.of_node, 0)); } static int mpc512x_psc_spi_of_remove(struct platform_device *op) From cd60080fd6200bd2e5ca9bf5135d32c06a8e6f3b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 18 Feb 2014 22:01:36 +0800 Subject: [PATCH 082/201] spi: omap2-mcspi: Remove list_empty checking in omap2_mcspi_transfer_one_message This checking is done in __spi_validate(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index 8f0afdb067b8..d90edaaa7f69 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1208,9 +1208,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, m->actual_length = 0; m->status = 0; - /* reject invalid messages and transfers */ - if (list_empty(&m->transfers)) - return -EINVAL; list_for_each_entry(t, &m->transfers, transfer_list) { const void *tx_buf = t->tx_buf; void *rx_buf = t->rx_buf; From aca0924b4819e813bdae2c595bf736ec2b593585 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 18 Feb 2014 22:02:47 +0800 Subject: [PATCH 083/201] spi: omap2-mcspi: Convert to let spi core validate transfer speed Set master->max_speed_hz and master->min_speed_hz then spi core will handle checking transfer speed. So we can remove the same checking in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-omap2-mcspi.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c index d90edaaa7f69..48d218e5fa01 100644 --- a/drivers/spi/spi-omap2-mcspi.c +++ b/drivers/spi/spi-omap2-mcspi.c @@ -1213,8 +1213,7 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, void *rx_buf = t->rx_buf; unsigned len = t->len; - if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ - || (len && !(rx_buf || tx_buf))) { + if ((len && !(rx_buf || tx_buf))) { dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", t->speed_hz, len, @@ -1223,12 +1222,6 @@ static int omap2_mcspi_transfer_one_message(struct spi_master *master, t->bits_per_word); return -EINVAL; } - if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) { - dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n", - t->speed_hz, - OMAP2_MCSPI_MAX_FREQ >> 15); - return -EINVAL; - } if (m->is_dma_mapped || len < DMA_MIN_BYTES) continue; @@ -1340,6 +1333,8 @@ static int omap2_mcspi_probe(struct platform_device *pdev) master->transfer_one_message = omap2_mcspi_transfer_one_message; master->cleanup = omap2_mcspi_cleanup; master->dev.of_node = node; + master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; + master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; platform_set_drvdata(pdev, master); From c1b20aa5d3b164a860e13b1bc5e85a24e45f0072 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 19 Feb 2014 10:36:09 +0100 Subject: [PATCH 084/201] spi/topcliff-pch: Fix debug message Signed-off-by: Alexander Stein Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 6304c91e6965..dc5d2d489953 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1116,8 +1116,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) dma->nent = num; dma->desc_tx = desc_tx; - dev_dbg(&data->master->dev, "\n%s:Pulling down SSN low - writing " - "0x2 to SSNXCR\n", __func__); + dev_dbg(&data->master->dev, "%s:Pulling down SSN low - writing 0x2 to SSNXCR\n", __func__); spin_lock_irqsave(&data->lock, flags); pch_spi_writereg(data->master, PCH_SSNXCR, SSN_LOW); From 1074600e79ad63b8986ae9b723b403984cf3408f Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Thu, 13 Feb 2014 18:21:23 +0200 Subject: [PATCH 085/201] spi: qup: Add device tree bindings information The Qualcomm Universal Peripheral (QUP) core is an AHB slave that provides a common data path (an output FIFO and an input FIFO) for serial peripheral interface (SPI) mini-core. Signed-off-by: Ivan T. Ivanov Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/qcom,spi-qup.txt | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/qcom,spi-qup.txt diff --git a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt new file mode 100644 index 000000000000..b82a268f1bd4 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt @@ -0,0 +1,85 @@ +Qualcomm Universal Peripheral (QUP) Serial Peripheral Interface (SPI) + +The QUP core is an AHB slave that provides a common data path (an output FIFO +and an input FIFO) for serial peripheral interface (SPI) mini-core. + +SPI in master mode supports up to 50MHz, up to four chip selects, programmable +data path from 4 bits to 32 bits and numerous protocol variants. + +Required properties: +- compatible: Should contain "qcom,spi-qup-v2.1.1" or "qcom,spi-qup-v2.2.1" +- reg: Should contain base register location and length +- interrupts: Interrupt number used by this controller + +- clocks: Should contain the core clock and the AHB clock. +- clock-names: Should be "core" for the core clock and "iface" for the + AHB clock. + +- #address-cells: Number of cells required to define a chip select + address on the SPI bus. Should be set to 1. +- #size-cells: Should be zero. + +Optional properties: +- spi-max-frequency: Specifies maximum SPI clock frequency, + Units - Hz. Definition as per + Documentation/devicetree/bindings/spi/spi-bus.txt + +SPI slave nodes must be children of the SPI master node and can contain +properties described in Documentation/devicetree/bindings/spi/spi-bus.txt + +Example: + + spi_8: spi@f9964000 { /* BLSP2 QUP2 */ + + compatible = "qcom,spi-qup-v2"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0xf9964000 0x1000>; + interrupts = <0 102 0>; + spi-max-frequency = <19200000>; + + clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>; + clock-names = "core", "iface"; + + pinctrl-names = "default"; + pinctrl-0 = <&spi8_default>; + + device@0 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0>; /* Chip select 0 */ + spi-max-frequency = <19200000>; + spi-cpol; + }; + + device@1 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <1>; /* Chip select 1 */ + spi-max-frequency = <9600000>; + spi-cpha; + }; + + device@2 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <2>; /* Chip select 2 */ + spi-max-frequency = <19200000>; + spi-cpol; + spi-cpha; + }; + + device@3 { + compatible = "arm,pl022-dummy"; + #address-cells = <1>; + #size-cells = <1>; + reg = <3>; /* Chip select 3 */ + spi-max-frequency = <19200000>; + spi-cpol; + spi-cpha; + spi-cs-high; + }; + }; From 64ff247a978facc437d40f0c9b754675846a98f0 Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Thu, 13 Feb 2014 18:21:38 +0200 Subject: [PATCH 086/201] spi: Add Qualcomm QUP SPI controller support Qualcomm Universal Peripheral (QUP) core is an AHB slave that provides a common data path (an output FIFO and an input FIFO) for serial peripheral interface (SPI) mini-core. SPI in master mode supports up to 50MHz, up to four chip selects, programmable data path from 4 bits to 32 bits and numerous protocol variants. Cc: Alok Chauhan Cc: Gilad Avidov Cc: Kiran Gunda Cc: Sagar Dharia Cc: dsneddon@codeaurora.org Signed-off-by: Ivan T. Ivanov Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 13 + drivers/spi/Makefile | 1 + drivers/spi/spi-qup.c | 837 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 851 insertions(+) create mode 100644 drivers/spi/spi-qup.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..86c254d76406 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -381,6 +381,19 @@ config SPI_RSPI help SPI driver for Renesas RSPI blocks. +config SPI_QUP + tristate "Qualcomm SPI controller with QUP interface" + depends on ARCH_MSM_DT + help + Qualcomm Universal Peripheral (QUP) core is an AHB slave that + provides a common data path (an output FIFO and an input FIFO) + for serial peripheral interface (SPI) mini-core. SPI in master + mode supports up to 50MHz, up to four chip selects, programmable + data path from 4 bits to 32 bits and numerous protocol variants. + + This driver can also be built as a module. If so, the module + will be called spi_qup. + config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" depends on ARCH_S3C24XX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 95af48d2d360..e598147b06ef 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -59,6 +59,7 @@ spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_PXADMA) += spi-pxa2xx-pxadma.o spi-pxa2xx-platform-$(CONFIG_SPI_PXA2XX_DMA) += spi-pxa2xx-dma.o obj-$(CONFIG_SPI_PXA2XX) += spi-pxa2xx-platform.o obj-$(CONFIG_SPI_PXA2XX_PCI) += spi-pxa2xx-pci.o +obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c new file mode 100644 index 000000000000..b0bcc09425a7 --- /dev/null +++ b/drivers/spi/spi-qup.c @@ -0,0 +1,837 @@ +/* + * Copyright (c) 2008-2014, The Linux foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License rev 2 and + * only rev 2 as published by the free Software foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define QUP_CONFIG 0x0000 +#define QUP_STATE 0x0004 +#define QUP_IO_M_MODES 0x0008 +#define QUP_SW_RESET 0x000c +#define QUP_OPERATIONAL 0x0018 +#define QUP_ERROR_FLAGS 0x001c +#define QUP_ERROR_FLAGS_EN 0x0020 +#define QUP_OPERATIONAL_MASK 0x0028 +#define QUP_HW_VERSION 0x0030 +#define QUP_MX_OUTPUT_CNT 0x0100 +#define QUP_OUTPUT_FIFO 0x0110 +#define QUP_MX_WRITE_CNT 0x0150 +#define QUP_MX_INPUT_CNT 0x0200 +#define QUP_MX_READ_CNT 0x0208 +#define QUP_INPUT_FIFO 0x0218 + +#define SPI_CONFIG 0x0300 +#define SPI_IO_CONTROL 0x0304 +#define SPI_ERROR_FLAGS 0x0308 +#define SPI_ERROR_FLAGS_EN 0x030c + +/* QUP_CONFIG fields */ +#define QUP_CONFIG_SPI_MODE (1 << 8) +#define QUP_CONFIG_CLOCK_AUTO_GATE BIT(13) +#define QUP_CONFIG_NO_INPUT BIT(7) +#define QUP_CONFIG_NO_OUTPUT BIT(6) +#define QUP_CONFIG_N 0x001f + +/* QUP_STATE fields */ +#define QUP_STATE_VALID BIT(2) +#define QUP_STATE_RESET 0 +#define QUP_STATE_RUN 1 +#define QUP_STATE_PAUSE 3 +#define QUP_STATE_MASK 3 +#define QUP_STATE_CLEAR 2 + +#define QUP_HW_VERSION_2_1_1 0x20010001 + +/* QUP_IO_M_MODES fields */ +#define QUP_IO_M_PACK_EN BIT(15) +#define QUP_IO_M_UNPACK_EN BIT(14) +#define QUP_IO_M_INPUT_MODE_MASK_SHIFT 12 +#define QUP_IO_M_OUTPUT_MODE_MASK_SHIFT 10 +#define QUP_IO_M_INPUT_MODE_MASK (3 << QUP_IO_M_INPUT_MODE_MASK_SHIFT) +#define QUP_IO_M_OUTPUT_MODE_MASK (3 << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT) + +#define QUP_IO_M_OUTPUT_BLOCK_SIZE(x) (((x) & (0x03 << 0)) >> 0) +#define QUP_IO_M_OUTPUT_FIFO_SIZE(x) (((x) & (0x07 << 2)) >> 2) +#define QUP_IO_M_INPUT_BLOCK_SIZE(x) (((x) & (0x03 << 5)) >> 5) +#define QUP_IO_M_INPUT_FIFO_SIZE(x) (((x) & (0x07 << 7)) >> 7) + +#define QUP_IO_M_MODE_FIFO 0 +#define QUP_IO_M_MODE_BLOCK 1 +#define QUP_IO_M_MODE_DMOV 2 +#define QUP_IO_M_MODE_BAM 3 + +/* QUP_OPERATIONAL fields */ +#define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11) +#define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10) +#define QUP_OP_IN_SERVICE_FLAG BIT(9) +#define QUP_OP_OUT_SERVICE_FLAG BIT(8) +#define QUP_OP_IN_FIFO_FULL BIT(7) +#define QUP_OP_OUT_FIFO_FULL BIT(6) +#define QUP_OP_IN_FIFO_NOT_EMPTY BIT(5) +#define QUP_OP_OUT_FIFO_NOT_EMPTY BIT(4) + +/* QUP_ERROR_FLAGS and QUP_ERROR_FLAGS_EN fields */ +#define QUP_ERROR_OUTPUT_OVER_RUN BIT(5) +#define QUP_ERROR_INPUT_UNDER_RUN BIT(4) +#define QUP_ERROR_OUTPUT_UNDER_RUN BIT(3) +#define QUP_ERROR_INPUT_OVER_RUN BIT(2) + +/* SPI_CONFIG fields */ +#define SPI_CONFIG_HS_MODE BIT(10) +#define SPI_CONFIG_INPUT_FIRST BIT(9) +#define SPI_CONFIG_LOOPBACK BIT(8) + +/* SPI_IO_CONTROL fields */ +#define SPI_IO_C_FORCE_CS BIT(11) +#define SPI_IO_C_CLK_IDLE_HIGH BIT(10) +#define SPI_IO_C_MX_CS_MODE BIT(8) +#define SPI_IO_C_CS_N_POLARITY_0 BIT(4) +#define SPI_IO_C_CS_SELECT(x) (((x) & 3) << 2) +#define SPI_IO_C_CS_SELECT_MASK 0x000c +#define SPI_IO_C_TRISTATE_CS BIT(1) +#define SPI_IO_C_NO_TRI_STATE BIT(0) + +/* SPI_ERROR_FLAGS and SPI_ERROR_FLAGS_EN fields */ +#define SPI_ERROR_CLK_OVER_RUN BIT(1) +#define SPI_ERROR_CLK_UNDER_RUN BIT(0) + +#define SPI_NUM_CHIPSELECTS 4 + +/* high speed mode is when bus rate is greater then 26MHz */ +#define SPI_HS_MIN_RATE 26000000 +#define SPI_MAX_RATE 50000000 + +#define SPI_DELAY_THRESHOLD 1 +#define SPI_DELAY_RETRY 10 + +struct spi_qup_device { + int select; + u16 mode; +}; + +struct spi_qup { + void __iomem *base; + struct device *dev; + struct clk *cclk; /* core clock */ + struct clk *iclk; /* interface clock */ + int irq; + u32 max_speed_hz; + spinlock_t lock; + + int in_fifo_sz; + int out_fifo_sz; + int in_blk_sz; + int out_blk_sz; + + struct spi_transfer *xfer; + struct completion done; + int error; + int w_size; /* bytes per SPI word */ + int tx_bytes; + int rx_bytes; +}; + + +static inline bool spi_qup_is_valid_state(struct spi_qup *controller) +{ + u32 opstate = readl_relaxed(controller->base + QUP_STATE); + + return opstate & QUP_STATE_VALID; +} + +static int spi_qup_set_state(struct spi_qup *controller, u32 state) +{ + unsigned long loop; + u32 cur_state; + + loop = 0; + while (!spi_qup_is_valid_state(controller)) { + + usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2); + + if (++loop > SPI_DELAY_RETRY) + return -EIO; + } + + if (loop) + dev_dbg(controller->dev, "invalid state for %ld,us %d\n", + loop, state); + + cur_state = readl_relaxed(controller->base + QUP_STATE); + /* + * Per spec: for PAUSE_STATE to RESET_STATE, two writes + * of (b10) are required + */ + if (((cur_state & QUP_STATE_MASK) == QUP_STATE_PAUSE) && + (state == QUP_STATE_RESET)) { + writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE); + writel_relaxed(QUP_STATE_CLEAR, controller->base + QUP_STATE); + } else { + cur_state &= ~QUP_STATE_MASK; + cur_state |= state; + writel_relaxed(cur_state, controller->base + QUP_STATE); + } + + loop = 0; + while (!spi_qup_is_valid_state(controller)) { + + usleep_range(SPI_DELAY_THRESHOLD, SPI_DELAY_THRESHOLD * 2); + + if (++loop > SPI_DELAY_RETRY) + return -EIO; + } + + return 0; +} + + +static void spi_qup_fifo_read(struct spi_qup *controller, + struct spi_transfer *xfer) +{ + u8 *rx_buf = xfer->rx_buf; + u32 word, state; + int idx, shift, w_size; + + w_size = controller->w_size; + + while (controller->rx_bytes < xfer->len) { + + state = readl_relaxed(controller->base + QUP_OPERATIONAL); + if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY)) + break; + + word = readl_relaxed(controller->base + QUP_INPUT_FIFO); + + if (!rx_buf) { + controller->rx_bytes += w_size; + continue; + } + + for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) { + /* + * The data format depends on bytes per SPI word: + * 4 bytes: 0x12345678 + * 2 bytes: 0x00001234 + * 1 byte : 0x00000012 + */ + shift = BITS_PER_BYTE; + shift *= (w_size - idx - 1); + rx_buf[controller->rx_bytes] = word >> shift; + } + } +} + +static void spi_qup_fifo_write(struct spi_qup *controller, + struct spi_transfer *xfer) +{ + const u8 *tx_buf = xfer->tx_buf; + u32 word, state, data; + int idx, w_size; + + w_size = controller->w_size; + + while (controller->tx_bytes < xfer->len) { + + state = readl_relaxed(controller->base + QUP_OPERATIONAL); + if (state & QUP_OP_OUT_FIFO_FULL) + break; + + word = 0; + for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) { + + if (!tx_buf) { + controller->tx_bytes += w_size; + break; + } + + data = tx_buf[controller->tx_bytes]; + word |= data << (BITS_PER_BYTE * (3 - idx)); + } + + writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO); + } +} + +static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) +{ + struct spi_qup *controller = dev_id; + struct spi_transfer *xfer; + u32 opflags, qup_err, spi_err; + unsigned long flags; + int error = 0; + + spin_lock_irqsave(&controller->lock, flags); + xfer = controller->xfer; + controller->xfer = NULL; + spin_unlock_irqrestore(&controller->lock, flags); + + qup_err = readl_relaxed(controller->base + QUP_ERROR_FLAGS); + spi_err = readl_relaxed(controller->base + SPI_ERROR_FLAGS); + opflags = readl_relaxed(controller->base + QUP_OPERATIONAL); + + writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS); + writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS); + writel_relaxed(opflags, controller->base + QUP_OPERATIONAL); + + if (!xfer) { + dev_err_ratelimited(controller->dev, "unexpected irq %x08 %x08 %x08\n", + qup_err, spi_err, opflags); + return IRQ_HANDLED; + } + + if (qup_err) { + if (qup_err & QUP_ERROR_OUTPUT_OVER_RUN) + dev_warn(controller->dev, "OUTPUT_OVER_RUN\n"); + if (qup_err & QUP_ERROR_INPUT_UNDER_RUN) + dev_warn(controller->dev, "INPUT_UNDER_RUN\n"); + if (qup_err & QUP_ERROR_OUTPUT_UNDER_RUN) + dev_warn(controller->dev, "OUTPUT_UNDER_RUN\n"); + if (qup_err & QUP_ERROR_INPUT_OVER_RUN) + dev_warn(controller->dev, "INPUT_OVER_RUN\n"); + + error = -EIO; + } + + if (spi_err) { + if (spi_err & SPI_ERROR_CLK_OVER_RUN) + dev_warn(controller->dev, "CLK_OVER_RUN\n"); + if (spi_err & SPI_ERROR_CLK_UNDER_RUN) + dev_warn(controller->dev, "CLK_UNDER_RUN\n"); + + error = -EIO; + } + + if (opflags & QUP_OP_IN_SERVICE_FLAG) + spi_qup_fifo_read(controller, xfer); + + if (opflags & QUP_OP_OUT_SERVICE_FLAG) + spi_qup_fifo_write(controller, xfer); + + spin_lock_irqsave(&controller->lock, flags); + controller->error = error; + controller->xfer = xfer; + spin_unlock_irqrestore(&controller->lock, flags); + + if (controller->rx_bytes == xfer->len || error) + complete(&controller->done); + + return IRQ_HANDLED; +} + + +/* set clock freq ... bits per word */ +static int spi_qup_io_config(struct spi_qup *controller, + struct spi_qup_device *chip, + struct spi_transfer *xfer) +{ + u32 config, iomode, mode; + int ret, n_words, w_size; + + if (chip->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { + dev_err(controller->dev, "too big size for loopback %d > %d\n", + xfer->len, controller->in_fifo_sz); + return -EIO; + } + + ret = clk_set_rate(controller->cclk, xfer->speed_hz); + if (ret) { + dev_err(controller->dev, "fail to set frequency %d", + xfer->speed_hz); + return -EIO; + } + + if (spi_qup_set_state(controller, QUP_STATE_RESET)) { + dev_err(controller->dev, "cannot set RESET state\n"); + return -EIO; + } + + w_size = 4; + if (xfer->bits_per_word <= 8) + w_size = 1; + else if (xfer->bits_per_word <= 16) + w_size = 2; + + n_words = xfer->len / w_size; + controller->w_size = w_size; + + if (n_words <= controller->in_fifo_sz) { + mode = QUP_IO_M_MODE_FIFO; + writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT); + writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT); + /* must be zero for FIFO */ + writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT); + writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT); + } else { + mode = QUP_IO_M_MODE_BLOCK; + writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT); + writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT); + /* must be zero for BLOCK and BAM */ + writel_relaxed(0, controller->base + QUP_MX_READ_CNT); + writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT); + } + + iomode = readl_relaxed(controller->base + QUP_IO_M_MODES); + /* Set input and output transfer mode */ + iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK); + iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN); + iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT); + iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT); + + writel_relaxed(iomode, controller->base + QUP_IO_M_MODES); + + config = readl_relaxed(controller->base + SPI_CONFIG); + + if (chip->mode & SPI_LOOP) + config |= SPI_CONFIG_LOOPBACK; + else + config &= ~SPI_CONFIG_LOOPBACK; + + if (chip->mode & SPI_CPHA) + config &= ~SPI_CONFIG_INPUT_FIRST; + else + config |= SPI_CONFIG_INPUT_FIRST; + + /* + * HS_MODE improves signal stability for spi-clk high rates, + * but is invalid in loop back mode. + */ + if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(chip->mode & SPI_LOOP)) + config |= SPI_CONFIG_HS_MODE; + else + config &= ~SPI_CONFIG_HS_MODE; + + writel_relaxed(config, controller->base + SPI_CONFIG); + + config = readl_relaxed(controller->base + QUP_CONFIG); + config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N); + config |= xfer->bits_per_word - 1; + config |= QUP_CONFIG_SPI_MODE; + writel_relaxed(config, controller->base + QUP_CONFIG); + + writel_relaxed(0, controller->base + QUP_OPERATIONAL_MASK); + return 0; +} + +static void spi_qup_set_cs(struct spi_device *spi, bool enable) +{ + struct spi_qup *controller = spi_master_get_devdata(spi->master); + struct spi_qup_device *chip = spi_get_ctldata(spi); + + u32 iocontol, mask; + + iocontol = readl_relaxed(controller->base + SPI_IO_CONTROL); + + /* Disable auto CS toggle and use manual */ + iocontol &= ~SPI_IO_C_MX_CS_MODE; + iocontol |= SPI_IO_C_FORCE_CS; + + iocontol &= ~SPI_IO_C_CS_SELECT_MASK; + iocontol |= SPI_IO_C_CS_SELECT(chip->select); + + mask = SPI_IO_C_CS_N_POLARITY_0 << chip->select; + + if (enable) + iocontol |= mask; + else + iocontol &= ~mask; + + writel_relaxed(iocontol, controller->base + SPI_IO_CONTROL); +} + +static int spi_qup_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct spi_qup *controller = spi_master_get_devdata(master); + struct spi_qup_device *chip = spi_get_ctldata(spi); + unsigned long timeout, flags; + int ret = -EIO; + + ret = spi_qup_io_config(controller, chip, xfer); + if (ret) + return ret; + + timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC); + timeout = DIV_ROUND_UP(xfer->len * 8, timeout); + timeout = 100 * msecs_to_jiffies(timeout); + + reinit_completion(&controller->done); + + spin_lock_irqsave(&controller->lock, flags); + controller->xfer = xfer; + controller->error = 0; + controller->rx_bytes = 0; + controller->tx_bytes = 0; + spin_unlock_irqrestore(&controller->lock, flags); + + if (spi_qup_set_state(controller, QUP_STATE_RUN)) { + dev_warn(controller->dev, "cannot set RUN state\n"); + goto exit; + } + + if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) { + dev_warn(controller->dev, "cannot set PAUSE state\n"); + goto exit; + } + + spi_qup_fifo_write(controller, xfer); + + if (spi_qup_set_state(controller, QUP_STATE_RUN)) { + dev_warn(controller->dev, "cannot set EXECUTE state\n"); + goto exit; + } + + if (!wait_for_completion_timeout(&controller->done, timeout)) + ret = -ETIMEDOUT; +exit: + spi_qup_set_state(controller, QUP_STATE_RESET); + spin_lock_irqsave(&controller->lock, flags); + controller->xfer = NULL; + if (!ret) + ret = controller->error; + spin_unlock_irqrestore(&controller->lock, flags); + return ret; +} + +static int spi_qup_setup(struct spi_device *spi) +{ + struct spi_qup *controller = spi_master_get_devdata(spi->master); + struct spi_qup_device *chip = spi_get_ctldata(spi); + + if (spi->chip_select >= spi->master->num_chipselect) { + dev_err(controller->dev, "invalid chip_select %d\n", + spi->chip_select); + return -EINVAL; + } + + if (spi->max_speed_hz > controller->max_speed_hz) { + dev_err(controller->dev, "invalid max_speed_hz %d\n", + spi->max_speed_hz); + return -EINVAL; + } + + if (!chip) { + /* First setup */ + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) { + dev_err(controller->dev, "no memory for chip data\n"); + return -ENOMEM; + } + + chip->mode = spi->mode; + chip->select = spi->chip_select; + spi_set_ctldata(spi, chip); + } + + return 0; +} + +static void spi_qup_cleanup(struct spi_device *spi) +{ + struct spi_qup_device *chip = spi_get_ctldata(spi); + + if (!chip) + return; + + spi_set_ctldata(spi, NULL); + kfree(chip); +} + +static int spi_qup_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct clk *iclk, *cclk; + struct spi_qup *controller; + struct resource *res; + struct device *dev; + void __iomem *base; + u32 data, max_freq, iomode; + int ret, irq, size; + + dev = &pdev->dev; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + irq = platform_get_irq(pdev, 0); + + if (irq < 0) + return irq; + + cclk = devm_clk_get(dev, "core"); + if (IS_ERR(cclk)) + return PTR_ERR(cclk); + + iclk = devm_clk_get(dev, "iface"); + if (IS_ERR(iclk)) + return PTR_ERR(iclk); + + /* This is optional parameter */ + if (of_property_read_u32(dev->of_node, "spi-max-frequency", &max_freq)) + max_freq = SPI_MAX_RATE; + + if (!max_freq || max_freq > SPI_MAX_RATE) { + dev_err(dev, "invalid clock frequency %d\n", max_freq); + return -ENXIO; + } + + ret = clk_prepare_enable(cclk); + if (ret) { + dev_err(dev, "cannot enable core clock\n"); + return ret; + } + + ret = clk_prepare_enable(iclk); + if (ret) { + clk_disable_unprepare(cclk); + dev_err(dev, "cannot enable iface clock\n"); + return ret; + } + + data = readl_relaxed(base + QUP_HW_VERSION); + + if (data < QUP_HW_VERSION_2_1_1) { + clk_disable_unprepare(cclk); + clk_disable_unprepare(iclk); + dev_err(dev, "v.%08x is not supported\n", data); + return -ENXIO; + } + + master = spi_alloc_master(dev, sizeof(struct spi_qup)); + if (!master) { + clk_disable_unprepare(cclk); + clk_disable_unprepare(iclk); + dev_err(dev, "cannot allocate master\n"); + return -ENOMEM; + } + + master->bus_num = pdev->id; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; + master->num_chipselect = SPI_NUM_CHIPSELECTS; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + master->setup = spi_qup_setup; + master->cleanup = spi_qup_cleanup; + master->set_cs = spi_qup_set_cs; + master->transfer_one = spi_qup_transfer_one; + master->dev.of_node = pdev->dev.of_node; + master->auto_runtime_pm = true; + + platform_set_drvdata(pdev, master); + + controller = spi_master_get_devdata(master); + + controller->dev = dev; + controller->base = base; + controller->iclk = iclk; + controller->cclk = cclk; + controller->irq = irq; + controller->max_speed_hz = max_freq; + + spin_lock_init(&controller->lock); + init_completion(&controller->done); + + iomode = readl_relaxed(base + QUP_IO_M_MODES); + + size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode); + if (size) + controller->out_blk_sz = size * 16; + else + controller->out_blk_sz = 4; + + size = QUP_IO_M_INPUT_BLOCK_SIZE(iomode); + if (size) + controller->in_blk_sz = size * 16; + else + controller->in_blk_sz = 4; + + size = QUP_IO_M_OUTPUT_FIFO_SIZE(iomode); + controller->out_fifo_sz = controller->out_blk_sz * (2 << size); + + size = QUP_IO_M_INPUT_FIFO_SIZE(iomode); + controller->in_fifo_sz = controller->in_blk_sz * (2 << size); + + dev_info(dev, "v.%08x IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n", + data, controller->in_blk_sz, controller->in_fifo_sz, + controller->out_blk_sz, controller->out_fifo_sz); + + writel_relaxed(1, base + QUP_SW_RESET); + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) { + dev_err(dev, "cannot set RESET state\n"); + goto error; + } + + writel_relaxed(0, base + QUP_OPERATIONAL); + writel_relaxed(0, base + QUP_IO_M_MODES); + writel_relaxed(0, base + QUP_OPERATIONAL_MASK); + writel_relaxed(SPI_ERROR_CLK_UNDER_RUN | SPI_ERROR_CLK_OVER_RUN, + base + SPI_ERROR_FLAGS_EN); + + writel_relaxed(0, base + SPI_CONFIG); + writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL); + + ret = devm_request_irq(dev, irq, spi_qup_qup_irq, + IRQF_TRIGGER_HIGH, pdev->name, controller); + if (ret) + goto error; + + ret = devm_spi_register_master(dev, master); + if (ret) + goto error; + + pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return 0; + +error: + clk_disable_unprepare(cclk); + clk_disable_unprepare(iclk); + spi_master_put(master); + return ret; +} + +#ifdef CONFIG_PM_RUNTIME +static int spi_qup_pm_suspend_runtime(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + u32 config; + + /* Enable clocks auto gaiting */ + config = readl(controller->base + QUP_CONFIG); + config |= QUP_CLOCK_AUTO_GATE; + writel_relaxed(config, controller->base + QUP_CONFIG); + return 0; +} + +static int spi_qup_pm_resume_runtime(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + u32 config; + + /* Disable clocks auto gaiting */ + config = readl_relaxed(controller->base + QUP_CONFIG); + config &= ~QUP_CLOCK_AUTO_GATE; + writel_relaxed(config, controller->base + QUP_CONFIG); + return 0; +} +#endif /* CONFIG_PM_RUNTIME */ + +#ifdef CONFIG_PM_SLEEP +static int spi_qup_suspend(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) + return ret; + + clk_disable_unprepare(controller->cclk); + clk_disable_unprepare(controller->iclk); + return 0; +} + +static int spi_qup_resume(struct device *device) +{ + struct spi_master *master = dev_get_drvdata(device); + struct spi_qup *controller = spi_master_get_devdata(master); + int ret; + + ret = clk_prepare_enable(controller->iclk); + if (ret) + return ret; + + ret = clk_prepare_enable(controller->cclk); + if (ret) + return ret; + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) + return ret; + + return spi_master_resume(master); +} +#endif /* CONFIG_PM_SLEEP */ + +static int spi_qup_remove(struct platform_device *pdev) +{ + struct spi_master *master = dev_get_drvdata(&pdev->dev); + struct spi_qup *controller = spi_master_get_devdata(master); + int ret; + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret) + return ret; + + ret = spi_qup_set_state(controller, QUP_STATE_RESET); + if (ret) + return ret; + + clk_disable_unprepare(controller->cclk); + clk_disable_unprepare(controller->iclk); + + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); + spi_master_put(master); + return 0; +} + +static struct of_device_id spi_qup_dt_match[] = { + { .compatible = "qcom,spi-qup-v2.1.1", }, + { .compatible = "qcom,spi-qup-v2.2.1", }, + { } +}; +MODULE_DEVICE_TABLE(of, spi_qup_dt_match); + +static const struct dev_pm_ops spi_qup_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(spi_qup_suspend, spi_qup_resume) + SET_RUNTIME_PM_OPS(spi_qup_pm_suspend_runtime, + spi_qup_pm_resume_runtime, + NULL) +}; + +static struct platform_driver spi_qup_driver = { + .driver = { + .name = "spi_qup", + .owner = THIS_MODULE, + .pm = &spi_qup_dev_pm_ops, + .of_match_table = spi_qup_dt_match, + }, + .probe = spi_qup_probe, + .remove = spi_qup_remove, +}; +module_platform_driver(spi_qup_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_VERSION("0.4"); +MODULE_ALIAS("platform:spi_qup"); From bf5c2e27036cffda6e20f445391a4d4e1ccc232e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 18 Feb 2014 17:15:54 +0800 Subject: [PATCH 087/201] spi: clps711x: Refactor to use core message parsing Convert to use default implementation of transfer_one_message() which provides standard handling of delays and chip select management. Signed-off-by: Axel Lin Tested-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 88 ++++++++++++++------------------------ 1 file changed, 33 insertions(+), 55 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index df086ee4cdaa..eda7472ceefa 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -25,8 +25,6 @@ #define DRIVER_NAME "spi-clps711x" struct spi_clps711x_data { - struct completion done; - struct clk *spi_clk; u32 max_speed_hz; @@ -44,15 +42,6 @@ static int spi_clps711x_setup(struct spi_device *spi) return 0; } -static void spi_clps711x_setup_mode(struct spi_device *spi) -{ - /* Setup edge for transfer */ - if (spi->mode & SPI_CPHA) - clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3); - else - clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3); -} - static void spi_clps711x_setup_xfer(struct spi_device *spi, struct spi_transfer *xfer) { @@ -74,55 +63,44 @@ static void spi_clps711x_setup_xfer(struct spi_device *spi, SYSCON1_ADCKSEL(0), SYSCON1); } -static int spi_clps711x_transfer_one_message(struct spi_master *master, - struct spi_message *msg) +static int spi_clps711x_prepare_message(struct spi_master *master, + struct spi_message *msg) { - struct spi_clps711x_data *hw = spi_master_get_devdata(master); struct spi_device *spi = msg->spi; - struct spi_transfer *xfer; - spi_clps711x_setup_mode(spi); - - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - u8 data; - - spi_clps711x_setup_xfer(spi, xfer); - - gpio_set_value(spi->cs_gpio, !!(spi->mode & SPI_CS_HIGH)); - - reinit_completion(&hw->done); - - hw->len = xfer->len; - hw->bpw = xfer->bits_per_word ? : spi->bits_per_word; - hw->tx_buf = (u8 *)xfer->tx_buf; - hw->rx_buf = (u8 *)xfer->rx_buf; - - /* Initiate transfer */ - data = hw->tx_buf ? *hw->tx_buf++ : 0; - clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, - SYNCIO); - - wait_for_completion(&hw->done); - - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); - - if (xfer->cs_change || - list_is_last(&xfer->transfer_list, &msg->transfers)) - gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); - - msg->actual_length += xfer->len; - } - - msg->status = 0; - spi_finalize_current_message(master); + /* Setup edge for transfer */ + if (spi->mode & SPI_CPHA) + clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3); + else + clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3); return 0; } +static int spi_clps711x_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + struct spi_clps711x_data *hw = spi_master_get_devdata(master); + u8 data; + + spi_clps711x_setup_xfer(spi, xfer); + + hw->len = xfer->len; + hw->bpw = xfer->bits_per_word ? : spi->bits_per_word; + hw->tx_buf = (u8 *)xfer->tx_buf; + hw->rx_buf = (u8 *)xfer->rx_buf; + + /* Initiate transfer */ + data = hw->tx_buf ? *hw->tx_buf++ : 0; + clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, SYNCIO); + return 1; +} + static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) { - struct spi_clps711x_data *hw = (struct spi_clps711x_data *)dev_id; + struct spi_master *master = dev_id; + struct spi_clps711x_data *hw = spi_master_get_devdata(master); u8 data; /* Handle RX */ @@ -136,7 +114,7 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, SYNCIO); } else - complete(&hw->done); + spi_finalize_current_transfer(master); return IRQ_HANDLED; } @@ -174,7 +152,8 @@ static int spi_clps711x_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 8); master->num_chipselect = pdata->num_chipselect; master->setup = spi_clps711x_setup; - master->transfer_one_message = spi_clps711x_transfer_one_message; + master->prepare_message = spi_clps711x_prepare_message; + master->transfer_one = spi_clps711x_transfer_one; hw = spi_master_get_devdata(master); @@ -200,7 +179,6 @@ static int spi_clps711x_probe(struct platform_device *pdev) } hw->max_speed_hz = clk_get_rate(hw->spi_clk); - init_completion(&hw->done); platform_set_drvdata(pdev, master); /* Disable extended mode due hardware problems */ @@ -210,7 +188,7 @@ static int spi_clps711x_probe(struct platform_device *pdev) clps_readl(SYNCIO); ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0, - dev_name(&pdev->dev), hw); + dev_name(&pdev->dev), master); if (ret) { dev_err(&pdev->dev, "Can't request IRQ\n"); goto err_out; From 4d94bd21b333c695eba97746b615e2efb30240cc Mon Sep 17 00:00:00 2001 From: "Ivan T. Ivanov" Date: Thu, 20 Feb 2014 12:02:08 +0200 Subject: [PATCH 088/201] spi: core: Validate length of the transfers in message SPI transfer length should be multiple of SPI word size, where SPI word size should be power-of-two multiple Signed-off-by: Ivan T. Ivanov Signed-off-by: Mark Brown --- drivers/spi/spi.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index bb660145d19e..1b53eee2cbca 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1617,6 +1617,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) { struct spi_master *master = spi->master; struct spi_transfer *xfer; + int w_size, n_words; if (list_empty(&message->transfers)) return -EINVAL; @@ -1668,6 +1669,22 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) return -EINVAL; } + /* + * SPI transfer length should be multiple of SPI word size + * where SPI word size should be power-of-two multiple + */ + if (xfer->bits_per_word <= 8) + w_size = 1; + else if (xfer->bits_per_word <= 16) + w_size = 2; + else + w_size = 4; + + n_words = xfer->len / w_size; + /* No partial transfers accepted */ + if (!n_words || xfer->len % w_size) + return -EINVAL; + if (xfer->speed_hz && master->min_speed_hz && xfer->speed_hz < master->min_speed_hz) return -EINVAL; From 925d16a209b40a3e7202a4f867991fb608834d36 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 16:01:43 +0100 Subject: [PATCH 089/201] spi/spidev_test: Document -N/--no-cs and -R/--ready commit b55f627feeb9d48fdbde3835e18afbc76712e49b ("spi: new spi->mode bits") added two new command line options without adding the respective help texts. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev_test.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index 16feda901469..efd7385e907f 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -81,7 +81,9 @@ static void print_usage(const char *prog) " -O --cpol clock polarity\n" " -L --lsb least significant bit first\n" " -C --cs-high chip select active high\n" - " -3 --3wire SI/SO signals shared\n"); + " -3 --3wire SI/SO signals shared\n" + " -N --no-cs no chip select\n" + " -R --ready slave pulls low to pause\n"); exit(1); } From f7c05e837df794d2aaf19174269a270c93a52eca Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:00 +0100 Subject: [PATCH 090/201] spi: sh-msiof: Fix SPI bus population from DT DT doesn't instantiate SPI children if spi_master.dev.of_node is not set up properly. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 81cc02f5f9b0..21ac8f668682 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -711,6 +711,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; master->flags = 0; master->bus_num = pdev->id; + master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; master->setup = spi_bitbang_setup; master->cleanup = spi_bitbang_cleanup; From a669c11a0df07477afbfeb53bc9d8fc989d1ed59 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:01 +0100 Subject: [PATCH 091/201] spi: sh-msiof: Typo in comment s/tx/rx/ Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 21ac8f668682..5eded247fce4 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -487,7 +487,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, /* clear status bits */ sh_msiof_reset_str(p); - /* shut down frame, tx/tx and clock signals */ + /* shut down frame, rx/tx and clock signals */ ret = sh_msiof_modify_ctr_wait(p, CTR_TFSE, 0); ret = ret ? ret : sh_msiof_modify_ctr_wait(p, CTR_TXE, 0); if (rx_buf) From 6a85fc5af1f09982e50abe56efc70eda9ad24632 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:02 +0100 Subject: [PATCH 092/201] spi: sh-msiof: Change hz from unsigned long to u32 Both spi_transfer.speed_hz and spi_master.max_speed_hz are u32 Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 5eded247fce4..d0af05e96a2d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -145,8 +145,7 @@ static struct { }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, - unsigned long parent_rate, - unsigned long spi_hz) + unsigned long parent_rate, u32 spi_hz) { unsigned long div = 1024; size_t k; @@ -373,10 +372,9 @@ static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t) return bits; } -static unsigned long sh_msiof_spi_hz(struct spi_device *spi, - struct spi_transfer *t) +static u32 sh_msiof_spi_hz(struct spi_device *spi, struct spi_transfer *t) { - unsigned long hz; + u32 hz; hz = t ? t->speed_hz : 0; if (!hz) From 01cfef57efe9c8ef445d4a5ad3bf26770fd5942a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:03 +0100 Subject: [PATCH 093/201] spi: sh-msiof: Add more register documentation Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 148 ++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 50 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index d0af05e96a2d..7acbc4052757 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -42,32 +42,80 @@ struct sh_msiof_spi_priv { int rx_fifo_size; }; -#define TMDR1 0x00 -#define TMDR2 0x04 -#define TMDR3 0x08 -#define RMDR1 0x10 -#define RMDR2 0x14 -#define RMDR3 0x18 -#define TSCR 0x20 -#define RSCR 0x22 -#define CTR 0x28 -#define FCTR 0x30 -#define STR 0x40 -#define IER 0x44 -#define TDR1 0x48 -#define TDR2 0x4c -#define TFDR 0x50 -#define RDR1 0x58 -#define RDR2 0x5c -#define RFDR 0x60 +#define TMDR1 0x00 /* Transmit Mode Register 1 */ +#define TMDR2 0x04 /* Transmit Mode Register 2 */ +#define TMDR3 0x08 /* Transmit Mode Register 3 */ +#define RMDR1 0x10 /* Receive Mode Register 1 */ +#define RMDR2 0x14 /* Receive Mode Register 2 */ +#define RMDR3 0x18 /* Receive Mode Register 3 */ +#define TSCR 0x20 /* Transmit Clock Select Register */ +#define RSCR 0x22 /* Receive Clock Select Register (SH, A1, APE6) */ +#define CTR 0x28 /* Control Register */ +#define FCTR 0x30 /* FIFO Control Register */ +#define STR 0x40 /* Status Register */ +#define IER 0x44 /* Interrupt Enable Register */ +#define TDR1 0x48 /* Transmit Control Data Register 1 (SH, A1) */ +#define TDR2 0x4c /* Transmit Control Data Register 2 (SH, A1) */ +#define TFDR 0x50 /* Transmit FIFO Data Register */ +#define RDR1 0x58 /* Receive Control Data Register 1 (SH, A1) */ +#define RDR2 0x5c /* Receive Control Data Register 2 (SH, A1) */ +#define RFDR 0x60 /* Receive FIFO Data Register */ -#define CTR_TSCKE (1 << 15) -#define CTR_TFSE (1 << 14) -#define CTR_TXE (1 << 9) -#define CTR_RXE (1 << 8) +/* TMDR1 and RMDR1 */ +#define MDR1_TRMD 0x80000000 /* Transfer Mode (1 = Master mode) */ +#define MDR1_SYNCMD_MASK 0x30000000 /* SYNC Mode */ +#define MDR1_SYNCMD_SPI 0x20000000 /* Level mode/SPI */ +#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */ +#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */ +#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */ +#define MDR1_FLD_MASK 0x000000c0 /* Frame Sync Signal Interval (0-3) */ +#define MDR1_FLD_SHIFT 2 +#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */ +/* TMDR1 */ +#define TMDR1_PCON 0x40000000 /* Transfer Signal Connection */ + +/* TMDR2 and RMDR2 */ +#define MDR2_BITLEN1(i) (((i) - 1) << 24) /* Data Size (8-32 bits) */ +#define MDR2_WDLEN1(i) (((i) - 1) << 16) /* Word Count (1-64/256 (SH, A1))) */ +#define MDR2_GRPMASK1 0x00000001 /* Group Output Mask 1 (SH, A1) */ + +/* TSCR and RSCR */ +#define SCR_BRPS_MASK 0x1f00 /* Prescaler Setting (1-32) */ +#define SCR_BRPS(i) (((i) - 1) << 8) +#define SCR_BRDV_MASK 0x0007 /* Baud Rate Generator's Division Ratio */ +#define SCR_BRDV_DIV_2 0x0000 +#define SCR_BRDV_DIV_4 0x0001 +#define SCR_BRDV_DIV_8 0x0002 +#define SCR_BRDV_DIV_16 0x0003 +#define SCR_BRDV_DIV_32 0x0004 +#define SCR_BRDV_DIV_1 0x0007 + +/* CTR */ +#define CTR_TSCKIZ_MASK 0xc0000000 /* Transmit Clock I/O Polarity Select */ +#define CTR_TSCKIZ_SCK 0x80000000 /* Disable SCK when TX disabled */ +#define CTR_TSCKIZ_POL_SHIFT 30 /* Transmit Clock Polarity */ +#define CTR_RSCKIZ_MASK 0x30000000 /* Receive Clock Polarity Select */ +#define CTR_RSCKIZ_SCK 0x20000000 /* Must match CTR_TSCKIZ_SCK */ +#define CTR_RSCKIZ_POL_SHIFT 28 /* Receive Clock Polarity */ +#define CTR_TEDG_SHIFT 27 /* Transmit Timing (1 = falling edge) */ +#define CTR_REDG_SHIFT 26 /* Receive Timing (1 = falling edge) */ +#define CTR_TXDIZ_MASK 0x00c00000 /* Pin Output When TX is Disabled */ +#define CTR_TXDIZ_LOW 0x00000000 /* 0 */ +#define CTR_TXDIZ_HIGH 0x00400000 /* 1 */ +#define CTR_TXDIZ_HIZ 0x00800000 /* High-impedance */ +#define CTR_TSCKE 0x00008000 /* Transmit Serial Clock Output Enable */ +#define CTR_TFSE 0x00004000 /* Transmit Frame Sync Signal Output Enable */ +#define CTR_TXE 0x00000200 /* Transmit Enable */ +#define CTR_RXE 0x00000100 /* Receive Enable */ + +/* STR and IER */ +#define STR_TEOF 0x00800000 /* Frame Transmission End */ +#define STR_REOF 0x00000080 /* Frame Reception End */ + + +#define DEFAULT_TX_FIFO_SIZE 64 +#define DEFAULT_RX_FIFO_SIZE 64 -#define STR_TEOF (1 << 23) -#define STR_REOF (1 << 7) static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) { @@ -131,17 +179,17 @@ static struct { unsigned short div; unsigned short scr; } const sh_msiof_spi_clk_table[] = { - { 1, 0x0007 }, - { 2, 0x0000 }, - { 4, 0x0001 }, - { 8, 0x0002 }, - { 16, 0x0003 }, - { 32, 0x0004 }, - { 64, 0x1f00 }, - { 128, 0x1f01 }, - { 256, 0x1f02 }, - { 512, 0x1f03 }, - { 1024, 0x1f04 }, + { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 }, + { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 }, + { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 }, + { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 }, + { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 }, + { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 }, + { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 }, + { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 }, + { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 }, + { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 }, + { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 }, }; static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, @@ -182,21 +230,21 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, */ sh_msiof_write(p, FCTR, 0); - tmp = 0; - tmp |= !cs_high << 25; - tmp |= lsb_first << 24; - sh_msiof_write(p, TMDR1, 0xe0000005 | tmp); - sh_msiof_write(p, RMDR1, 0x20000005 | tmp); + tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP; + tmp |= !cs_high << MDR1_SYNCAC_SHIFT; + tmp |= lsb_first << MDR1_BITLSB_SHIFT; + sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); + sh_msiof_write(p, RMDR1, tmp); - tmp = 0xa0000000; - tmp |= cpol << 30; /* TSCKIZ */ - tmp |= cpol << 28; /* RSCKIZ */ + tmp = 0; + tmp |= CTR_TSCKIZ_SCK | cpol << CTR_TSCKIZ_POL_SHIFT; + tmp |= CTR_RSCKIZ_SCK | cpol << CTR_RSCKIZ_POL_SHIFT; edge = cpol ^ !cpha; - tmp |= edge << 27; /* TEDG */ - tmp |= edge << 26; /* REDG */ - tmp |= (tx_hi_z ? 2 : 0) << 22; /* TXDIZ */ + tmp |= edge << CTR_TEDG_SHIFT; + tmp |= edge << CTR_REDG_SHIFT; + tmp |= tx_hi_z ? CTR_TXDIZ_HIZ : CTR_TXDIZ_LOW; sh_msiof_write(p, CTR, tmp); } @@ -204,12 +252,12 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, const void *tx_buf, void *rx_buf, u32 bits, u32 words) { - u32 dr2 = ((bits - 1) << 24) | ((words - 1) << 16); + u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words); if (tx_buf) sh_msiof_write(p, TMDR2, dr2); else - sh_msiof_write(p, TMDR2, dr2 | 1); + sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1); if (rx_buf) sh_msiof_write(p, RMDR2, dr2); @@ -695,8 +743,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); /* The standard version of MSIOF use 64 word FIFOs */ - p->tx_fifo_size = 64; - p->rx_fifo_size = 64; + p->tx_fifo_size = DEFAULT_TX_FIFO_SIZE; + p->rx_fifo_size = DEFAULT_RX_FIFO_SIZE; /* Platform data may override FIFO sizes */ if (p->info->tx_fifo_override) From 8d19534a8d539bb2e598e56e017a423f205e909e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 20 Feb 2014 15:43:04 +0100 Subject: [PATCH 094/201] spi: sh-msiof: Use the core cs_gpio field, and make it optional In current implementation, CS is controlled by GPIO, which is passed through spi->controller_data. However, the MSIOF HW module has a function to output CS by itself, which is already enabled and actual switch will be done by pinmux. Store the GPIO number in the core cs_gpio field, and ignore it if it is an invalid (negative) GPIO number. Loosely based on a patch from Takashi Yoshii . Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 7acbc4052757..6e2ba62ceb63 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -446,6 +446,21 @@ static int sh_msiof_spi_setup_transfer(struct spi_device *spi, return spi_bitbang_setup_transfer(spi, t); } +static int sh_msiof_spi_setup(struct spi_device *spi) +{ + struct device_node *np = spi->master->dev.of_node; + + if (!np) { + /* + * Use spi->controller_data for CS (same strategy as spi_gpio), + * if any. otherwise let HW control CS + */ + spi->cs_gpio = (uintptr_t)spi->controller_data; + } + + return spi_bitbang_setup(spi); +} + static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) { struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); @@ -471,8 +486,8 @@ static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) !!(spi->mode & SPI_CS_HIGH)); } - /* use spi->controller data for CS (same strategy as spi_gpio) */ - gpio_set_value((uintptr_t)spi->controller_data, value); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, value); if (is_on == BITBANG_CS_INACTIVE) { if (test_and_clear_bit(0, &p->flags)) { @@ -759,7 +774,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; - master->setup = spi_bitbang_setup; + master->setup = sh_msiof_spi_setup; master->cleanup = spi_bitbang_cleanup; p->bitbang.master = master; From d00694167bd0f3ccdf5176451e6ca400d923538b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 22 Feb 2014 17:38:24 -0300 Subject: [PATCH 095/201] spi/imx: Drop default setting for SPI_IMX SPI_IMX is selected by imx_v6_v7_defconfig/imx_v4_v5_defconfig and we don't need to have a default setting which depends on the IMX_HAVE_PLATFORM_SPI_IMX symbol. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..7f6a3a31110f 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -212,7 +212,6 @@ config SPI_IMX tristate "Freescale i.MX SPI controllers" depends on ARCH_MXC || COMPILE_TEST select SPI_BITBANG - default m if IMX_HAVE_PLATFORM_SPI_IMX help This enables using the Freescale i.MX SPI controllers in master mode. From 8fc39b516623f3beed18be701d2acfe0e50b8d86 Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Feb 2014 17:23:46 +0400 Subject: [PATCH 096/201] spi/imx: Use dev_name() for request_irq() to distinguish SPIs Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/spi/spi-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index ad6daf510d33..d2e08c4b5cc5 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -885,7 +885,7 @@ static int spi_imx_probe(struct platform_device *pdev) } ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0, - DRIVER_NAME, spi_imx); + dev_name(&pdev->dev), spi_imx); if (ret) { dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret); goto out_master_put; From b5f6517948cce50bde9aa441b4f00b63518f6421 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Sat, 22 Feb 2014 22:35:53 +0100 Subject: [PATCH 097/201] spi: sunxi: Add Allwinner A10 SPI controller driver The older Allwinner SoCs (A10, A13, A10s and A20) all have the same SPI controller. Unfortunately, this SPI controller, even though quite similar, is significantly different from the recently supported A31 SPI controller (different registers offset, split/merged registers, etc.). Supporting both controllers in a single driver would be unreasonable, hence the addition of a new driver. Like its more recent counterpart, it supports DMA, but the driver only does PIO until we have a dmaengine driver for this platform. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-sun4i.txt | 24 + drivers/spi/Kconfig | 6 + drivers/spi/Makefile | 1 + drivers/spi/spi-sun4i.c | 477 ++++++++++++++++++ 4 files changed, 508 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-sun4i.txt create mode 100644 drivers/spi/spi-sun4i.c diff --git a/Documentation/devicetree/bindings/spi/spi-sun4i.txt b/Documentation/devicetree/bindings/spi/spi-sun4i.txt new file mode 100644 index 000000000000..de827f5a301e --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-sun4i.txt @@ -0,0 +1,24 @@ +Allwinner A10 SPI controller + +Required properties: +- compatible: Should be "allwinner,sun4-a10-spi". +- reg: Should contain register location and length. +- interrupts: Should contain interrupt. +- clocks: phandle to the clocks feeding the SPI controller. Two are + needed: + - "ahb": the gated AHB parent clock + - "mod": the parent module clock +- clock-names: Must contain the clock names described just above + +Example: + +spi1: spi@01c06000 { + compatible = "allwinner,sun4i-a10-spi"; + reg = <0x01c06000 0x1000>; + interrupts = <11>; + clocks = <&ahb_gates 21>, <&spi1_clk>; + clock-names = "ahb", "mod"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; +}; diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 0ec46415145d..5dffdc1691e8 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -446,6 +446,12 @@ config SPI_SIRF help SPI driver for CSR SiRFprimaII SoCs +config SPI_SUN4I + tristate "Allwinner A10 SoCs SPI controller" + depends on ARCH_SUNXI || COMPILE_TEST + help + SPI driver for Allwinner sun4i, sun5i and sun7i SoCs + config SPI_SUN6I tristate "Allwinner A31 SPI controller" depends on ARCH_SUNXI || COMPILE_TEST diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 13b6ccf904d9..65f4993ab083 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o obj-$(CONFIG_SPI_SIRF) += spi-sirf.o +obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c new file mode 100644 index 000000000000..3f82705d0a27 --- /dev/null +++ b/drivers/spi/spi-sun4i.c @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2012 - 2014 Allwinner Tech + * Pan Nan + * + * Copyright (C) 2014 Maxime Ripard + * Maxime Ripard + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SUN4I_FIFO_DEPTH 64 + +#define SUN4I_RXDATA_REG 0x00 + +#define SUN4I_TXDATA_REG 0x04 + +#define SUN4I_CTL_REG 0x08 +#define SUN4I_CTL_ENABLE BIT(0) +#define SUN4I_CTL_MASTER BIT(1) +#define SUN4I_CTL_CPHA BIT(2) +#define SUN4I_CTL_CPOL BIT(3) +#define SUN4I_CTL_CS_ACTIVE_LOW BIT(4) +#define SUN4I_CTL_LMTF BIT(6) +#define SUN4I_CTL_TF_RST BIT(8) +#define SUN4I_CTL_RF_RST BIT(9) +#define SUN4I_CTL_XCH BIT(10) +#define SUN4I_CTL_CS_MASK 0x3000 +#define SUN4I_CTL_CS(cs) (((cs) << 12) & SUN4I_CTL_CS_MASK) +#define SUN4I_CTL_DHB BIT(15) +#define SUN4I_CTL_CS_MANUAL BIT(16) +#define SUN4I_CTL_CS_LEVEL BIT(17) +#define SUN4I_CTL_TP BIT(18) + +#define SUN4I_INT_CTL_REG 0x0c +#define SUN4I_INT_CTL_TC BIT(16) + +#define SUN4I_INT_STA_REG 0x10 + +#define SUN4I_DMA_CTL_REG 0x14 + +#define SUN4I_WAIT_REG 0x18 + +#define SUN4I_CLK_CTL_REG 0x1c +#define SUN4I_CLK_CTL_CDR2_MASK 0xff +#define SUN4I_CLK_CTL_CDR2(div) ((div) & SUN4I_CLK_CTL_CDR2_MASK) +#define SUN4I_CLK_CTL_CDR1_MASK 0xf +#define SUN4I_CLK_CTL_CDR1(div) (((div) & SUN4I_CLK_CTL_CDR1_MASK) << 8) +#define SUN4I_CLK_CTL_DRS BIT(12) + +#define SUN4I_BURST_CNT_REG 0x20 +#define SUN4I_BURST_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN4I_XMIT_CNT_REG 0x24 +#define SUN4I_XMIT_CNT(cnt) ((cnt) & 0xffffff) + +#define SUN4I_FIFO_STA_REG 0x28 +#define SUN4I_FIFO_STA_RF_CNT_MASK 0x7f +#define SUN4I_FIFO_STA_RF_CNT_BITS 0 +#define SUN4I_FIFO_STA_TF_CNT_MASK 0x7f +#define SUN4I_FIFO_STA_TF_CNT_BITS 16 + +struct sun4i_spi { + struct spi_master *master; + void __iomem *base_addr; + struct clk *hclk; + struct clk *mclk; + + struct completion done; + + const u8 *tx_buf; + u8 *rx_buf; + int len; +}; + +static inline u32 sun4i_spi_read(struct sun4i_spi *sspi, u32 reg) +{ + return readl(sspi->base_addr + reg); +} + +static inline void sun4i_spi_write(struct sun4i_spi *sspi, u32 reg, u32 value) +{ + writel(value, sspi->base_addr + reg); +} + +static inline void sun4i_spi_drain_fifo(struct sun4i_spi *sspi, int len) +{ + u32 reg, cnt; + u8 byte; + + /* See how much data is available */ + reg = sun4i_spi_read(sspi, SUN4I_FIFO_STA_REG); + reg &= SUN4I_FIFO_STA_RF_CNT_MASK; + cnt = reg >> SUN4I_FIFO_STA_RF_CNT_BITS; + + if (len > cnt) + len = cnt; + + while (len--) { + byte = readb(sspi->base_addr + SUN4I_RXDATA_REG); + if (sspi->rx_buf) + *sspi->rx_buf++ = byte; + } +} + +static inline void sun4i_spi_fill_fifo(struct sun4i_spi *sspi, int len) +{ + u8 byte; + + if (len > sspi->len) + len = sspi->len; + + while (len--) { + byte = sspi->tx_buf ? *sspi->tx_buf++ : 0; + writeb(byte, sspi->base_addr + SUN4I_TXDATA_REG); + sspi->len--; + } +} + +static void sun4i_spi_set_cs(struct spi_device *spi, bool enable) +{ + struct sun4i_spi *sspi = spi_master_get_devdata(spi->master); + u32 reg; + + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); + + reg &= ~SUN4I_CTL_CS_MASK; + reg |= SUN4I_CTL_CS(spi->chip_select); + + if (enable) + reg |= SUN4I_CTL_CS_LEVEL; + else + reg &= ~SUN4I_CTL_CS_LEVEL; + + /* + * Even though this looks irrelevant since we are supposed to + * be controlling the chip select manually, this bit also + * controls the levels of the chip select for inactive + * devices. + * + * If we don't set it, the chip select level will go low by + * default when the device is idle, which is not really + * expected in the common case where the chip select is active + * low. + */ + if (spi->mode & SPI_CS_HIGH) + reg &= ~SUN4I_CTL_CS_ACTIVE_LOW; + else + reg |= SUN4I_CTL_CS_ACTIVE_LOW; + + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); +} + +static int sun4i_spi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *tfr) +{ + struct sun4i_spi *sspi = spi_master_get_devdata(master); + unsigned int mclk_rate, div, timeout; + unsigned int tx_len = 0; + int ret = 0; + u32 reg; + + /* We don't support transfer larger than the FIFO */ + if (tfr->len > SUN4I_FIFO_DEPTH) + return -EINVAL; + + reinit_completion(&sspi->done); + sspi->tx_buf = tfr->tx_buf; + sspi->rx_buf = tfr->rx_buf; + sspi->len = tfr->len; + + /* Clear pending interrupts */ + sun4i_spi_write(sspi, SUN4I_INT_STA_REG, ~0); + + + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); + + /* Reset FIFOs */ + sun4i_spi_write(sspi, SUN4I_CTL_REG, + reg | SUN4I_CTL_RF_RST | SUN4I_CTL_TF_RST); + + /* + * Setup the transfer control register: Chip Select, + * polarities, etc. + */ + if (spi->mode & SPI_CPOL) + reg |= SUN4I_CTL_CPOL; + else + reg &= ~SUN4I_CTL_CPOL; + + if (spi->mode & SPI_CPHA) + reg |= SUN4I_CTL_CPHA; + else + reg &= ~SUN4I_CTL_CPHA; + + if (spi->mode & SPI_LSB_FIRST) + reg |= SUN4I_CTL_LMTF; + else + reg &= ~SUN4I_CTL_LMTF; + + + /* + * If it's a TX only transfer, we don't want to fill the RX + * FIFO with bogus data + */ + if (sspi->rx_buf) + reg &= ~SUN4I_CTL_DHB; + else + reg |= SUN4I_CTL_DHB; + + /* We want to control the chip select manually */ + reg |= SUN4I_CTL_CS_MANUAL; + + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg); + + /* Ensure that we have a parent clock fast enough */ + mclk_rate = clk_get_rate(sspi->mclk); + if (mclk_rate < (2 * spi->max_speed_hz)) { + clk_set_rate(sspi->mclk, 2 * spi->max_speed_hz); + mclk_rate = clk_get_rate(sspi->mclk); + } + + /* + * Setup clock divider. + * + * We have two choices there. Either we can use the clock + * divide rate 1, which is calculated thanks to this formula: + * SPI_CLK = MOD_CLK / (2 ^ (cdr + 1)) + * Or we can use CDR2, which is calculated with the formula: + * SPI_CLK = MOD_CLK / (2 * (cdr + 1)) + * Wether we use the former or the latter is set through the + * DRS bit. + * + * First try CDR2, and if we can't reach the expected + * frequency, fall back to CDR1. + */ + div = mclk_rate / (2 * spi->max_speed_hz); + if (div <= (SUN4I_CLK_CTL_CDR2_MASK + 1)) { + if (div > 0) + div--; + + reg = SUN4I_CLK_CTL_CDR2(div) | SUN4I_CLK_CTL_DRS; + } else { + div = ilog2(mclk_rate) - ilog2(spi->max_speed_hz); + reg = SUN4I_CLK_CTL_CDR1(div); + } + + sun4i_spi_write(sspi, SUN4I_CLK_CTL_REG, reg); + + /* Setup the transfer now... */ + if (sspi->tx_buf) + tx_len = tfr->len; + + /* Setup the counters */ + sun4i_spi_write(sspi, SUN4I_BURST_CNT_REG, SUN4I_BURST_CNT(tfr->len)); + sun4i_spi_write(sspi, SUN4I_XMIT_CNT_REG, SUN4I_XMIT_CNT(tx_len)); + + /* Fill the TX FIFO */ + sun4i_spi_fill_fifo(sspi, SUN4I_FIFO_DEPTH); + + /* Enable the interrupts */ + sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, SUN4I_INT_CTL_TC); + + /* Start the transfer */ + reg = sun4i_spi_read(sspi, SUN4I_CTL_REG); + sun4i_spi_write(sspi, SUN4I_CTL_REG, reg | SUN4I_CTL_XCH); + + timeout = wait_for_completion_timeout(&sspi->done, + msecs_to_jiffies(1000)); + if (!timeout) { + ret = -ETIMEDOUT; + goto out; + } + + sun4i_spi_drain_fifo(sspi, SUN4I_FIFO_DEPTH); + +out: + sun4i_spi_write(sspi, SUN4I_INT_CTL_REG, 0); + + return ret; +} + +static irqreturn_t sun4i_spi_handler(int irq, void *dev_id) +{ + struct sun4i_spi *sspi = dev_id; + u32 status = sun4i_spi_read(sspi, SUN4I_INT_STA_REG); + + /* Transfer complete */ + if (status & SUN4I_INT_CTL_TC) { + sun4i_spi_write(sspi, SUN4I_INT_STA_REG, SUN4I_INT_CTL_TC); + complete(&sspi->done); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int sun4i_spi_runtime_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun4i_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = clk_prepare_enable(sspi->hclk); + if (ret) { + dev_err(dev, "Couldn't enable AHB clock\n"); + goto out; + } + + ret = clk_prepare_enable(sspi->mclk); + if (ret) { + dev_err(dev, "Couldn't enable module clock\n"); + goto err; + } + + sun4i_spi_write(sspi, SUN4I_CTL_REG, + SUN4I_CTL_ENABLE | SUN4I_CTL_MASTER | SUN4I_CTL_TP); + + return 0; + +err: + clk_disable_unprepare(sspi->hclk); +out: + return ret; +} + +static int sun4i_spi_runtime_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + struct sun4i_spi *sspi = spi_master_get_devdata(master); + + clk_disable_unprepare(sspi->mclk); + clk_disable_unprepare(sspi->hclk); + + return 0; +} + +static int sun4i_spi_probe(struct platform_device *pdev) +{ + struct spi_master *master; + struct sun4i_spi *sspi; + struct resource *res; + int ret = 0, irq; + + master = spi_alloc_master(&pdev->dev, sizeof(struct sun4i_spi)); + if (!master) { + dev_err(&pdev->dev, "Unable to allocate SPI Master\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, master); + sspi = spi_master_get_devdata(master); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sspi->base_addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(sspi->base_addr)) { + ret = PTR_ERR(sspi->base_addr); + goto err_free_master; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "No spi IRQ specified\n"); + ret = -ENXIO; + goto err_free_master; + } + + ret = devm_request_irq(&pdev->dev, irq, sun4i_spi_handler, + 0, "sun4i-spi", sspi); + if (ret) { + dev_err(&pdev->dev, "Cannot request IRQ\n"); + goto err_free_master; + } + + sspi->master = master; + master->set_cs = sun4i_spi_set_cs; + master->transfer_one = sun4i_spi_transfer_one; + master->num_chipselect = 4; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + master->dev.of_node = pdev->dev.of_node; + master->auto_runtime_pm = true; + + sspi->hclk = devm_clk_get(&pdev->dev, "ahb"); + if (IS_ERR(sspi->hclk)) { + dev_err(&pdev->dev, "Unable to acquire AHB clock\n"); + ret = PTR_ERR(sspi->hclk); + goto err_free_master; + } + + sspi->mclk = devm_clk_get(&pdev->dev, "mod"); + if (IS_ERR(sspi->mclk)) { + dev_err(&pdev->dev, "Unable to acquire module clock\n"); + ret = PTR_ERR(sspi->mclk); + goto err_free_master; + } + + init_completion(&sspi->done); + + /* + * This wake-up/shutdown pattern is to be able to have the + * device woken up, even if runtime_pm is disabled + */ + ret = sun4i_spi_runtime_resume(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Couldn't resume the device\n"); + goto err_free_master; + } + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); + if (ret) { + dev_err(&pdev->dev, "cannot register SPI master\n"); + goto err_pm_disable; + } + + return 0; + +err_pm_disable: + pm_runtime_disable(&pdev->dev); + sun4i_spi_runtime_suspend(&pdev->dev); +err_free_master: + spi_master_put(master); + return ret; +} + +static int sun4i_spi_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static const struct of_device_id sun4i_spi_match[] = { + { .compatible = "allwinner,sun4i-a10-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, sun4i_spi_match); + +static const struct dev_pm_ops sun4i_spi_pm_ops = { + .runtime_resume = sun4i_spi_runtime_resume, + .runtime_suspend = sun4i_spi_runtime_suspend, +}; + +static struct platform_driver sun4i_spi_driver = { + .probe = sun4i_spi_probe, + .remove = sun4i_spi_remove, + .driver = { + .name = "sun4i-spi", + .owner = THIS_MODULE, + .of_match_table = sun4i_spi_match, + .pm = &sun4i_spi_pm_ops, + }, +}; +module_platform_driver(sun4i_spi_driver); + +MODULE_AUTHOR("Pan Nan "); +MODULE_AUTHOR("Maxime Ripard "); +MODULE_DESCRIPTION("Allwinner A1X/A20 SPI controller driver"); +MODULE_LICENSE("GPL"); From a971fbf6c845972d3bd51a880052c1c9be499c90 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Feb 2014 17:29:15 +0100 Subject: [PATCH 098/201] spi: rspi: List full example compatible properties in bindings List full example compatible properties with soctypes instead of just the soctypes, so checkpatch can validate DTSes. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rspi.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt index 95f9b21d239f..e54924b2aff6 100644 --- a/Documentation/devicetree/bindings/spi/spi-rspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt @@ -7,9 +7,11 @@ Required properties: "renesas,rspi-", "renesas,rspi-rz" as fallback. For Quad Serial Peripheral Interface on R-Car Gen2: "renesas,qspi-", "renesas,qspi" as fallback. - Examples of valid soctypes are "sh7757" (SH), - "r7s72100" (RZ/A1H), "r8a7790" (R-Car H2), and - "r8a7791" (R-Car M2). + Examples with soctypes are: + - "renesas,rspi-sh7757" (SH) + - "renesas,rspi-r7s72100" (RZ/A1H) + - "renesas,qspi-r8a7790" (R-Car H2) + - "renesas,qspi-r8a7791" (R-Car M2) - reg : Address start and address range size of the device - interrupts : A list of interrupt-specifiers, one for each entry in interrupt-names. From 3d90e43ee1432dab4a119c709553686fc5e6f447 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Feb 2014 17:29:16 +0100 Subject: [PATCH 099/201] spi: rspi: Remove bogus colon in formatting Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi-rspi.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi-rspi.txt b/Documentation/devicetree/bindings/spi/spi-rspi.txt index e54924b2aff6..d57d82a74054 100644 --- a/Documentation/devicetree/bindings/spi/spi-rspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-rspi.txt @@ -29,7 +29,7 @@ Required properties: - #size-cells : Must be <0> Optional properties: -- clocks: : Must contain a reference to the functional clock. +- clocks : Must contain a reference to the functional clock. Pinctrl properties might be needed, too. See Documentation/devicetree/bindings/pinctrl/renesas,*. From ab98fcba962a57cee9fdb97aff2b25248c93cea5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Feb 2014 17:29:17 +0100 Subject: [PATCH 100/201] spi: rspi: Remove empty rspi_cleanup() If spi_master.cleanup() is not needed, it can be left unimplemented. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 04528888a53f..4a1f978c3381 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -893,10 +893,6 @@ static int rspi_setup(struct spi_device *spi) return 0; } -static void rspi_cleanup(struct spi_device *spi) -{ -} - static u16 qspi_transfer_mode(const struct spi_transfer *xfer) { if (xfer->tx_buf) @@ -1255,7 +1251,6 @@ static int rspi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->setup = rspi_setup; master->transfer_one = ops->transfer_one; - master->cleanup = rspi_cleanup; master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; master->mode_bits = ops->mode_bits; From ba824d4971691a7f1f66429e378a08a95fbb5b79 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 21 Feb 2014 17:29:18 +0100 Subject: [PATCH 101/201] spi: rspi: Fix loopback mode for Dual/Quad SPI Transfers While normal Dual and Quad SPI Transfers are unidirectional, we must do a bidirectional transfer if loopback mode is enabled, else rx_buf is not filled. With spidev it seemed to work, as spidev uses the same buffer for tranmission and reception. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 4a1f978c3381..92bec7e91046 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -859,7 +859,9 @@ static int qspi_transfer_one(struct spi_master *master, struct spi_device *spi, { struct rspi_data *rspi = spi_master_get_devdata(master); - if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) { + if (spi->mode & SPI_LOOP) { + return qspi_transfer_out_in(rspi, xfer); + } else if (xfer->tx_buf && xfer->tx_nbits > SPI_NBITS_SINGLE) { /* Quad or Dual SPI Write */ return qspi_transfer_out(rspi, xfer); } else if (xfer->rx_buf && xfer->rx_nbits > SPI_NBITS_SINGLE) { From 81b045fe72f957ad24ab97f999ea8ca14359d941 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Feb 2014 09:33:16 +0800 Subject: [PATCH 102/201] spi: qup: Remove spi_master_put in spi_qup_remove This driver uses devm_spi_register_master() so don't explicitly call spi_master_put() in spi_qup_remove(). Signed-off-by: Axel Lin Acked-by: Ivan T. Ivanov Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index b0bcc09425a7..5edc56f5c887 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -802,7 +802,6 @@ static int spi_qup_remove(struct platform_device *pdev) pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); - spi_master_put(master); return 0; } From cb64ca54076243b1d88b0a8430504d0a4cf3a5fa Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Feb 2014 09:34:16 +0800 Subject: [PATCH 103/201] spi: qup: Convert ot let spi core handle checking transfer speed Set master->max_speed_hz then spi core will handle checking transfer speed. So we can remove the same checking in this driver. Also remove checking spi->chip_select in spi_qup_setup(), the checking is done by spi core. Signed-off-by: Axel Lin Acked-by: Ivan T. Ivanov Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 5edc56f5c887..dec339d51fc8 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -134,7 +134,6 @@ struct spi_qup { struct clk *cclk; /* core clock */ struct clk *iclk; /* interface clock */ int irq; - u32 max_speed_hz; spinlock_t lock; int in_fifo_sz; @@ -517,18 +516,6 @@ static int spi_qup_setup(struct spi_device *spi) struct spi_qup *controller = spi_master_get_devdata(spi->master); struct spi_qup_device *chip = spi_get_ctldata(spi); - if (spi->chip_select >= spi->master->num_chipselect) { - dev_err(controller->dev, "invalid chip_select %d\n", - spi->chip_select); - return -EINVAL; - } - - if (spi->max_speed_hz > controller->max_speed_hz) { - dev_err(controller->dev, "invalid max_speed_hz %d\n", - spi->max_speed_hz); - return -EINVAL; - } - if (!chip) { /* First setup */ chip = kzalloc(sizeof(*chip), GFP_KERNEL); @@ -629,6 +616,7 @@ static int spi_qup_probe(struct platform_device *pdev) master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; master->num_chipselect = SPI_NUM_CHIPSELECTS; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); + master->max_speed_hz = max_freq; master->setup = spi_qup_setup; master->cleanup = spi_qup_cleanup; master->set_cs = spi_qup_set_cs; @@ -645,7 +633,6 @@ static int spi_qup_probe(struct platform_device *pdev) controller->iclk = iclk; controller->cclk = cclk; controller->irq = irq; - controller->max_speed_hz = max_freq; spin_lock_init(&controller->lock); init_completion(&controller->done); From 4522193698d115761f9e4f340697f86975ac8e69 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Feb 2014 22:09:52 +0800 Subject: [PATCH 104/201] spi: sh-hspi: Convert to let spi core validate bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 82d2f922ffa0..dbd2c44f95e9 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -230,21 +230,6 @@ static int hspi_transfer_one_message(struct spi_master *master, return ret; } -static int hspi_setup(struct spi_device *spi) -{ - struct hspi_priv *hspi = spi_master_get_devdata(spi->master); - struct device *dev = hspi->dev; - - if (8 != spi->bits_per_word) { - dev_err(dev, "bits_per_word should be 8\n"); - return -EIO; - } - - dev_dbg(dev, "%s setup\n", spi->modalias); - - return 0; -} - static void hspi_cleanup(struct spi_device *spi) { struct hspi_priv *hspi = spi_master_get_devdata(spi->master); @@ -300,12 +285,13 @@ static int hspi_probe(struct platform_device *pdev) master->num_chipselect = 1; master->bus_num = pdev->id; - master->setup = hspi_setup; master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; master->transfer_one_message = hspi_transfer_one_message; + master->bits_per_word_mask = SPI_BPW_MASK(8); + ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); From 23e2c2aa45a213ea25636ac5add66c2507e7361b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Feb 2014 22:13:27 +0800 Subject: [PATCH 105/201] spi: Use list_last_entry at appropriate places Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 3 +-- drivers/spi/spi-pl022.c | 5 ++--- drivers/spi/spi-pxa2xx.c | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index bf98d63d92b3..390da9bf2d84 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -276,8 +276,7 @@ static void giveback(struct dw_spi *dws) queue_work(dws->workqueue, &dws->pump_messages); spin_unlock_irqrestore(&dws->lock, flags); - last_transfer = list_entry(msg->transfers.prev, - struct spi_transfer, + last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, transfer_list); if (!last_transfer->cs_change && dws->cs_control) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 2789b452e711..3c5b90559bec 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -459,9 +459,8 @@ static void giveback(struct pl022 *pl022) struct spi_transfer *last_transfer; pl022->next_msg_cs_active = false; - last_transfer = list_entry(pl022->cur_msg->transfers.prev, - struct spi_transfer, - transfer_list); + last_transfer = list_last_entry(&pl022->cur_msg->transfers, + struct spi_transfer, transfer_list); /* Delay if requested before any change in chip select */ if (last_transfer->delay_usecs) diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index c702fc536a77..41185d0557fa 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -362,8 +362,7 @@ static void giveback(struct driver_data *drv_data) drv_data->cur_msg = NULL; drv_data->cur_transfer = NULL; - last_transfer = list_entry(msg->transfers.prev, - struct spi_transfer, + last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, transfer_list); /* Delay if requested before any change in chip select */ From 9bf46f6df5d1e9db8b4b786d22e88d8b6edd949e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Feb 2014 21:06:43 +0800 Subject: [PATCH 106/201] spi: xilinx: Convert to let spi core validate bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. spi_bitbang requires custom setup_transfer() to be defined if there is a custom txrx_bufs(). Thus keep the empty xilinx_spi_setup_transfer() function in the code. Signed-off-by: Axel Lin Acked-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 6d4ce4615163..4eb1ed9ab6da 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -209,26 +209,11 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on) } /* spi_bitbang requires custom setup_transfer() to be defined if there is a - * custom txrx_bufs(). We have nothing to setup here as the SPI IP block - * supports 8 or 16 bits per word which cannot be changed in software. - * SPI clock can't be changed in software either. - * Check for correct bits per word. Chip select delay calculations could be - * added here as soon as bitbang_work() can be made aware of the delay value. + * custom txrx_bufs(). */ static int xilinx_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { - struct xilinx_spi *xspi = spi_master_get_devdata(spi->master); - u8 bits_per_word; - - bits_per_word = (t && t->bits_per_word) - ? t->bits_per_word : spi->bits_per_word; - if (bits_per_word != xspi->bits_per_word) { - dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", - __func__, bits_per_word); - return -EINVAL; - } - return 0; } @@ -407,6 +392,7 @@ static int xilinx_spi_probe(struct platform_device *pdev) xspi->write_fn = xspi_write32_be; } + master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word); xspi->bits_per_word = bits_per_word; if (xspi->bits_per_word == 8) { xspi->tx_fn = xspi_tx8; From f734394d861fe71eafa28d6c28199d9847c5a319 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 13 Feb 2014 19:05:38 +0800 Subject: [PATCH 107/201] spi: fsl-spi: Convert to let spi core validate xfer->bits_per_word Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. fsl_spi_grlib_probe() may update mpc8xxx_spi->max_bits_per_word setting. So set master->bits_per_word_mask after fsl_spi_grlib_probe(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-spi.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c index 4dcb2929c01f..f35488ed62a9 100644 --- a/drivers/spi/spi-fsl-spi.c +++ b/drivers/spi/spi-fsl-spi.c @@ -239,12 +239,6 @@ static int fsl_spi_setup_transfer(struct spi_device *spi, if (!bits_per_word) bits_per_word = spi->bits_per_word; - /* Make sure its a bit width we support [4..16, 32] */ - if ((bits_per_word < 4) - || ((bits_per_word > 16) && (bits_per_word != 32)) - || (bits_per_word > mpc8xxx_spi->max_bits_per_word)) - return -EINVAL; - if (!hz) hz = spi->max_speed_hz; @@ -651,6 +645,10 @@ static struct spi_master * fsl_spi_probe(struct device *dev, if (mpc8xxx_spi->type == TYPE_GRLIB) fsl_spi_grlib_probe(dev); + master->bits_per_word_mask = + (SPI_BPW_RANGE_MASK(4, 16) | SPI_BPW_MASK(32)) & + SPI_BPW_RANGE_MASK(1, mpc8xxx_spi->max_bits_per_word); + if (mpc8xxx_spi->flags & SPI_QE_CPU_MODE) mpc8xxx_spi->set_shifts = fsl_spi_qe_cpu_set_shifts; From f97b26b05b1dcd307b2f79d1f9e9d99551987dbb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Feb 2014 09:15:18 +0800 Subject: [PATCH 108/201] spi: core: Replace msleep with usleep_range to get more accurate sleep time Fixes below checkpatch warning: WARNING: msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt + msleep(10); Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 1b53eee2cbca..d5ee965fb285 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -892,7 +892,7 @@ static int spi_stop_queue(struct spi_master *master) */ while ((!list_empty(&master->queue) || master->busy) && limit--) { spin_unlock_irqrestore(&master->queue_lock, flags); - msleep(10); + usleep_range(10000, 11000); spin_lock_irqsave(&master->queue_lock, flags); } From f0ceb114aec78cc585b8e7cb3d536f8a3e386bf1 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 23 Feb 2014 13:27:16 +0800 Subject: [PATCH 109/201] spi: qup: Fix build error due to a typo Fix below build error when CONFIG_PM_RUNTIME=y: C [M] drivers/spi/spi-qup.o drivers/spi/spi-qup.c: In function 'spi_qup_pm_suspend_runtime': drivers/spi/spi-qup.c:712:12: error: 'QUP_CLOCK_AUTO_GATE' undeclared (first use in this function) drivers/spi/spi-qup.c:712:12: note: each undeclared identifier is reported only once for each function it appears in drivers/spi/spi-qup.c: In function 'spi_qup_pm_resume_runtime': drivers/spi/spi-qup.c:725:13: error: 'QUP_CLOCK_AUTO_GATE' undeclared (first use in this function) make[2]: *** [drivers/spi/spi-qup.o] Error 1 make[1]: *** [drivers/spi] Error 2 make: *** [drivers] Error 2 Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index dec339d51fc8..886edb4f4cb0 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -709,7 +709,7 @@ static int spi_qup_pm_suspend_runtime(struct device *device) /* Enable clocks auto gaiting */ config = readl(controller->base + QUP_CONFIG); - config |= QUP_CLOCK_AUTO_GATE; + config |= QUP_CONFIG_CLOCK_AUTO_GATE; writel_relaxed(config, controller->base + QUP_CONFIG); return 0; } @@ -722,7 +722,7 @@ static int spi_qup_pm_resume_runtime(struct device *device) /* Disable clocks auto gaiting */ config = readl_relaxed(controller->base + QUP_CONFIG); - config &= ~QUP_CLOCK_AUTO_GATE; + config &= ~QUP_CONFIG_CLOCK_AUTO_GATE; writel_relaxed(config, controller->base + QUP_CONFIG); return 0; } From 702d3cf9d05dbb2dc145bc97aeff6c4d61bec70f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 23 Feb 2014 13:28:33 +0800 Subject: [PATCH 110/201] spi: qup: Enable driver compilation with COMPILE_TEST This helps increasing build testing coverage. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index 86c254d76406..f0351d88085e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -383,7 +383,7 @@ config SPI_RSPI config SPI_QUP tristate "Qualcomm SPI controller with QUP interface" - depends on ARCH_MSM_DT + depends on ARCH_MSM_DT || COMPILE_TEST help Qualcomm Universal Peripheral (QUP) core is an AHB slave that provides a common data path (an output FIFO and an input FIFO) From dd7243d6a5de6faaef30cebc554ce8b39d5a3de5 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Thu, 13 Feb 2014 00:30:19 +0800 Subject: [PATCH 111/201] spi: sirf: move to use generic dma dt-binding sirf-dma driver enabled generic dt binding for dma channels. see here we remove self-defined dma channel prop and move to use generic dma_request_slave_channel. related changes in dts is something like: dmas = <&dmac1 9>, <&dmac1 4>; dma-names = "rx", "tx"; Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 632d2b5b821f..61e5eafac92c 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -22,7 +22,6 @@ #include #include #include -#include #define DRIVER_NAME "sirfsoc_spi" @@ -539,8 +538,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) struct spi_master *master; struct resource *mem_res; int num_cs, cs_gpio, irq; - u32 rx_dma_ch, tx_dma_ch; - dma_cap_mask_t dma_cap_mask; int i; int ret; @@ -551,20 +548,6 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) goto err_cs; } - ret = of_property_read_u32(pdev->dev.of_node, - "sirf,spi-dma-rx-channel", &rx_dma_ch); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get rx dma channel\n"); - goto err_cs; - } - - ret = of_property_read_u32(pdev->dev.of_node, - "sirf,spi-dma-tx-channel", &tx_dma_ch); - if (ret < 0) { - dev_err(&pdev->dev, "Unable to get tx dma channel\n"); - goto err_cs; - } - master = spi_alloc_master(&pdev->dev, sizeof(*sspi) + sizeof(int) * num_cs); if (!master) { dev_err(&pdev->dev, "Unable to allocate SPI master\n"); @@ -628,18 +611,13 @@ static int spi_sirfsoc_probe(struct platform_device *pdev) sspi->bitbang.master->dev.of_node = pdev->dev.of_node; /* request DMA channels */ - dma_cap_zero(dma_cap_mask); - dma_cap_set(DMA_INTERLEAVE, dma_cap_mask); - - sspi->rx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)rx_dma_ch); + sspi->rx_chan = dma_request_slave_channel(&pdev->dev, "rx"); if (!sspi->rx_chan) { dev_err(&pdev->dev, "can not allocate rx dma channel\n"); ret = -ENODEV; goto free_master; } - sspi->tx_chan = dma_request_channel(dma_cap_mask, (dma_filter_fn)sirfsoc_dma_filter_id, - (void *)tx_dma_ch); + sspi->tx_chan = dma_request_slave_channel(&pdev->dev, "tx"); if (!sspi->tx_chan) { dev_err(&pdev->dev, "can not allocate tx dma channel\n"); ret = -ENODEV; From facffed29709313593e6feab3a08d9664874e977 Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Thu, 13 Feb 2014 00:30:20 +0800 Subject: [PATCH 112/201] spi: sirf: use SET_SYSTEM_SLEEP_PM_OPS to initialize PM entries use SET_SYSTEM_SLEEP_PM_OPS to initialize PM entries, this makes the codes clean and also enable the ability of hibernation support for sirf SPI. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 61e5eafac92c..5210b94729aa 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -693,7 +693,7 @@ static int spi_sirfsoc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int spi_sirfsoc_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); @@ -716,12 +716,11 @@ static int spi_sirfsoc_resume(struct device *dev) return 0; } +#endif static const struct dev_pm_ops spi_sirfsoc_pm_ops = { - .suspend = spi_sirfsoc_suspend, - .resume = spi_sirfsoc_resume, + SET_SYSTEM_SLEEP_PM_OPS(spi_sirfsoc_suspend, spi_sirfsoc_resume) }; -#endif static const struct of_device_id spi_sirfsoc_of_match[] = { { .compatible = "sirf,prima2-spi", }, @@ -734,9 +733,7 @@ static struct platform_driver spi_sirfsoc_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &spi_sirfsoc_pm_ops, -#endif .of_match_table = spi_sirfsoc_of_match, }, .probe = spi_sirfsoc_probe, From 80faf90f9734a06eb4da2e3b92e698b96f469c2c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Feb 2014 12:07:51 +0800 Subject: [PATCH 113/201] spi: qup: Depend on ARM && COMPILE_TEST to avoid build error This driver uses writel_relaxed() which does not exist in x86, ppc, etc. Make it depend on ARM && COMPILE_TEST to avoid below build error: CC [M] drivers/spi/spi-qup.o drivers/spi/spi-qup.c: In function 'spi_qup_set_state': drivers/spi/spi-qup.c:180:3: error: implicit declaration of function 'writel_relaxed' [-Werror=implicit-function-declaration] cc1: some warnings being treated as errors make[2]: *** [drivers/spi/spi-qup.o] Error 1 make[1]: *** [drivers/spi] Error 2 make: *** [drivers] Error 2 Reported-by: Stephen Rothwell Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index f0351d88085e..082acbdef1bd 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -383,7 +383,7 @@ config SPI_RSPI config SPI_QUP tristate "Qualcomm SPI controller with QUP interface" - depends on ARCH_MSM_DT || COMPILE_TEST + depends on ARCH_MSM_DT || (ARM && COMPILE_TEST) help Qualcomm Universal Peripheral (QUP) core is an AHB slave that provides a common data path (an output FIFO and an input FIFO) From 83f091440db9ba3f739522cee0c627ecfe1cc8ef Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Feb 2014 13:48:12 +0800 Subject: [PATCH 114/201] spi: qup: Remove module version The module version is unlikely to be updated, use kernel version should be enough. Signed-off-by: Axel Lin Acked-by: Ivan T. Ivanov Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 886edb4f4cb0..203f0d4f049f 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -819,5 +819,4 @@ static struct platform_driver spi_qup_driver = { module_platform_driver(spi_qup_driver); MODULE_LICENSE("GPL v2"); -MODULE_VERSION("0.4"); MODULE_ALIAS("platform:spi_qup"); From 382ab20e8138083966b7bde141d3c6a79dda68bf Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Feb 2014 19:18:29 +0800 Subject: [PATCH 115/201] spi: s3c64xx: Let spi core handle validating transfer length spi core will handle validating transfer length since commit 4d94bd21b333 "spi: core: Validate length of the transfers in message". So remove the same checking in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-s3c64xx.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 9ad5e3e76b96..f19cd97855e8 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -697,13 +697,6 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master, bpw = xfer->bits_per_word; speed = xfer->speed_hz ? : spi->max_speed_hz; - if (xfer->len % (bpw / 8)) { - dev_err(&spi->dev, - "Xfer length(%u) not a multiple of word size(%u)\n", - xfer->len, bpw / 8); - return -EIO; - } - if (bpw != sdd->cur_bpw || speed != sdd->cur_speed) { sdd->cur_bpw = bpw; sdd->cur_speed = speed; From 00cce74d081e86ee0660cbe41699cbc523a55605 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Feb 2014 23:07:36 +0800 Subject: [PATCH 116/201] spi: qup: Get rid of using struct spi_qup_device Current code uses struct spi_qup_device to store spi->mode and spi->chip_select settings. We can get these settings in spi_qup_transfer_one and spi_qup_set_cs without using struct spi_qup_device. Refactor the code a bit to remove spi_qup_setup(), spi_qup_cleanup(), and struct spi_qup_device. Signed-off-by: Axel Lin Tested-by: Ivan T. Ivanov Signed-off-by: Mark Brown --- drivers/spi/spi-qup.c | 61 +++++++------------------------------------ 1 file changed, 9 insertions(+), 52 deletions(-) diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c index 203f0d4f049f..b032e8885e24 100644 --- a/drivers/spi/spi-qup.c +++ b/drivers/spi/spi-qup.c @@ -123,11 +123,6 @@ #define SPI_DELAY_THRESHOLD 1 #define SPI_DELAY_RETRY 10 -struct spi_qup_device { - int select; - u16 mode; -}; - struct spi_qup { void __iomem *base; struct device *dev; @@ -338,14 +333,13 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id) /* set clock freq ... bits per word */ -static int spi_qup_io_config(struct spi_qup *controller, - struct spi_qup_device *chip, - struct spi_transfer *xfer) +static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer) { + struct spi_qup *controller = spi_master_get_devdata(spi->master); u32 config, iomode, mode; int ret, n_words, w_size; - if (chip->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { + if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) { dev_err(controller->dev, "too big size for loopback %d > %d\n", xfer->len, controller->in_fifo_sz); return -EIO; @@ -399,12 +393,12 @@ static int spi_qup_io_config(struct spi_qup *controller, config = readl_relaxed(controller->base + SPI_CONFIG); - if (chip->mode & SPI_LOOP) + if (spi->mode & SPI_LOOP) config |= SPI_CONFIG_LOOPBACK; else config &= ~SPI_CONFIG_LOOPBACK; - if (chip->mode & SPI_CPHA) + if (spi->mode & SPI_CPHA) config &= ~SPI_CONFIG_INPUT_FIRST; else config |= SPI_CONFIG_INPUT_FIRST; @@ -413,7 +407,7 @@ static int spi_qup_io_config(struct spi_qup *controller, * HS_MODE improves signal stability for spi-clk high rates, * but is invalid in loop back mode. */ - if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(chip->mode & SPI_LOOP)) + if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP)) config |= SPI_CONFIG_HS_MODE; else config &= ~SPI_CONFIG_HS_MODE; @@ -433,7 +427,6 @@ static int spi_qup_io_config(struct spi_qup *controller, static void spi_qup_set_cs(struct spi_device *spi, bool enable) { struct spi_qup *controller = spi_master_get_devdata(spi->master); - struct spi_qup_device *chip = spi_get_ctldata(spi); u32 iocontol, mask; @@ -444,9 +437,9 @@ static void spi_qup_set_cs(struct spi_device *spi, bool enable) iocontol |= SPI_IO_C_FORCE_CS; iocontol &= ~SPI_IO_C_CS_SELECT_MASK; - iocontol |= SPI_IO_C_CS_SELECT(chip->select); + iocontol |= SPI_IO_C_CS_SELECT(spi->chip_select); - mask = SPI_IO_C_CS_N_POLARITY_0 << chip->select; + mask = SPI_IO_C_CS_N_POLARITY_0 << spi->chip_select; if (enable) iocontol |= mask; @@ -461,11 +454,10 @@ static int spi_qup_transfer_one(struct spi_master *master, struct spi_transfer *xfer) { struct spi_qup *controller = spi_master_get_devdata(master); - struct spi_qup_device *chip = spi_get_ctldata(spi); unsigned long timeout, flags; int ret = -EIO; - ret = spi_qup_io_config(controller, chip, xfer); + ret = spi_qup_io_config(spi, xfer); if (ret) return ret; @@ -511,38 +503,6 @@ exit: return ret; } -static int spi_qup_setup(struct spi_device *spi) -{ - struct spi_qup *controller = spi_master_get_devdata(spi->master); - struct spi_qup_device *chip = spi_get_ctldata(spi); - - if (!chip) { - /* First setup */ - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) { - dev_err(controller->dev, "no memory for chip data\n"); - return -ENOMEM; - } - - chip->mode = spi->mode; - chip->select = spi->chip_select; - spi_set_ctldata(spi, chip); - } - - return 0; -} - -static void spi_qup_cleanup(struct spi_device *spi) -{ - struct spi_qup_device *chip = spi_get_ctldata(spi); - - if (!chip) - return; - - spi_set_ctldata(spi, NULL); - kfree(chip); -} - static int spi_qup_probe(struct platform_device *pdev) { struct spi_master *master; @@ -561,7 +521,6 @@ static int spi_qup_probe(struct platform_device *pdev) return PTR_ERR(base); irq = platform_get_irq(pdev, 0); - if (irq < 0) return irq; @@ -617,8 +576,6 @@ static int spi_qup_probe(struct platform_device *pdev) master->num_chipselect = SPI_NUM_CHIPSELECTS; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->max_speed_hz = max_freq; - master->setup = spi_qup_setup; - master->cleanup = spi_qup_cleanup; master->set_cs = spi_qup_set_cs; master->transfer_one = spi_qup_transfer_one; master->dev.of_node = pdev->dev.of_node; From 6ff8672a96a01ec0861784b23be48a32443269f7 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:24:47 +0900 Subject: [PATCH 117/201] spi: xilinx: remove unnecessary spaces Remove unnecessary space in order to fix the following checkpatch issues. WARNING: Unnecessary space after function pointer name Signed-off-by: Jingoo Han Reviewed-by: Michal Simek Signed-off-by: Mark Brown --- drivers/spi/spi-xilinx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c index 4eb1ed9ab6da..85082a85ee37 100644 --- a/drivers/spi/spi-xilinx.c +++ b/drivers/spi/spi-xilinx.c @@ -88,10 +88,10 @@ struct xilinx_spi { const u8 *tx_ptr; /* pointer in the Rx buffer */ int remaining_bytes; /* the number of bytes left to transfer */ u8 bits_per_word; - unsigned int (*read_fn) (void __iomem *); - void (*write_fn) (u32, void __iomem *); - void (*tx_fn) (struct xilinx_spi *); - void (*rx_fn) (struct xilinx_spi *); + unsigned int (*read_fn)(void __iomem *); + void (*write_fn)(u32, void __iomem *); + void (*tx_fn)(struct xilinx_spi *); + void (*rx_fn)(struct xilinx_spi *); }; static void xspi_write32(u32 val, void __iomem *addr) From 71aa2e3207ad3249b4a7ceff7ca775a08341fdcb Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:32:48 +0900 Subject: [PATCH 118/201] spi: sirf: Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Acked-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 5210b94729aa..dc962a17f373 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -718,9 +718,8 @@ static int spi_sirfsoc_resume(struct device *dev) } #endif -static const struct dev_pm_ops spi_sirfsoc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(spi_sirfsoc_suspend, spi_sirfsoc_resume) -}; +static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend, + spi_sirfsoc_resume); static const struct of_device_id spi_sirfsoc_of_match[] = { { .compatible = "sirf,prima2-spi", }, From e6456186cae76f80446ba911f77eb2f85d3d927e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:16 +0100 Subject: [PATCH 119/201] spi: spidev: Restore all SPI mode flags on ioctl failure In commit f477b7fb13df2b843997559ff34e87d054ba6538 ("spi: DUAL and QUAD support"), spi_device.mode was enlarged from 8 to 16 bits. However, the spidev code still only saved 8 bits of data. If a spidev SPI_IOC_WR_MODE or SPI_IOC_WR_LSB_FIRST request failed, only the lower 8 bits of the SPI mode were restored, inadvertently clearing the upper 8 bits, possibly disabling Quad or Dual SPI transfers for the device. Save up to 32 bits to fix this. For SPI_IOC_WR_MODE this is probably not so important, as it doesn't allow setting Quad or Dual mode anyway, but SPI_IOC_WR_LSB_FIRST is used to just set or clear a single bit. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spidev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index d7c6e36021e8..2abc0f5a82be 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -374,7 +374,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case SPI_IOC_WR_MODE: retval = __get_user(tmp, (u8 __user *)arg); if (retval == 0) { - u8 save = spi->mode; + u32 save = spi->mode; if (tmp & ~SPI_MODE_MASK) { retval = -EINVAL; @@ -393,7 +393,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case SPI_IOC_WR_LSB_FIRST: retval = __get_user(tmp, (__u8 __user *)arg); if (retval == 0) { - u8 save = spi->mode; + u32 save = spi->mode; if (tmp) spi->mode |= SPI_LSB_FIRST; From dc64d39b54c1e9db97a6fb1ca52598c981728157 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:17 +0100 Subject: [PATCH 120/201] spi: spidev: Add support for Dual/Quad SPI Transfers Add support for Dual/Quad SPI Transfers to the spidev API. As this uses SPI mode bits that don't fit in a single byte, two new ioctls (SPI_IOC_RD_MODE32 and SPI_IOC_WR_MODE32) are introduced. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev | 6 ++++++ drivers/spi/spidev.c | 19 +++++++++++++++---- include/uapi/linux/spi/spidev.h | 14 ++++++++++++-- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/Documentation/spi/spidev b/Documentation/spi/spidev index ed2da5e5b28a..3d14035b1766 100644 --- a/Documentation/spi/spidev +++ b/Documentation/spi/spidev @@ -85,6 +85,12 @@ settings for data transfer parameters: SPI_MODE_0..SPI_MODE_3; or if you prefer you can combine SPI_CPOL (clock polarity, idle high iff this is set) or SPI_CPHA (clock phase, sample on trailing edge iff this is set) flags. + Note that this request is limited to SPI mode flags that fit in a + single byte. + + SPI_IOC_RD_MODE32, SPI_IOC_WR_MODE32 ... pass a pointer to a uin32_t + which will return (RD) or assign (WR) the full SPI transfer mode, + not limited to the bits that fit in one byte. SPI_IOC_RD_LSB_FIRST, SPI_IOC_WR_LSB_FIRST ... pass a pointer to a byte which will return (RD) or assign (WR) the bit justification used to diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c index 2abc0f5a82be..e3bc23bb5883 100644 --- a/drivers/spi/spidev.c +++ b/drivers/spi/spidev.c @@ -73,7 +73,8 @@ static DECLARE_BITMAP(minors, N_SPI_MINORS); */ #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \ | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \ - | SPI_NO_CS | SPI_READY) + | SPI_NO_CS | SPI_READY | SPI_TX_DUAL \ + | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD) struct spidev_data { dev_t devt; @@ -265,6 +266,8 @@ static int spidev_message(struct spidev_data *spidev, buf += k_tmp->len; k_tmp->cs_change = !!u_tmp->cs_change; + k_tmp->tx_nbits = u_tmp->tx_nbits; + k_tmp->rx_nbits = u_tmp->rx_nbits; k_tmp->bits_per_word = u_tmp->bits_per_word; k_tmp->delay_usecs = u_tmp->delay_usecs; k_tmp->speed_hz = u_tmp->speed_hz; @@ -359,6 +362,10 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = __put_user(spi->mode & SPI_MODE_MASK, (__u8 __user *)arg); break; + case SPI_IOC_RD_MODE32: + retval = __put_user(spi->mode & SPI_MODE_MASK, + (__u32 __user *)arg); + break; case SPI_IOC_RD_LSB_FIRST: retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0, (__u8 __user *)arg); @@ -372,7 +379,11 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /* write requests */ case SPI_IOC_WR_MODE: - retval = __get_user(tmp, (u8 __user *)arg); + case SPI_IOC_WR_MODE32: + if (cmd == SPI_IOC_WR_MODE) + retval = __get_user(tmp, (u8 __user *)arg); + else + retval = __get_user(tmp, (u32 __user *)arg); if (retval == 0) { u32 save = spi->mode; @@ -382,12 +393,12 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } tmp |= spi->mode & ~SPI_MODE_MASK; - spi->mode = (u8)tmp; + spi->mode = (u16)tmp; retval = spi_setup(spi); if (retval < 0) spi->mode = save; else - dev_dbg(&spi->dev, "spi mode %02x\n", tmp); + dev_dbg(&spi->dev, "spi mode %x\n", tmp); } break; case SPI_IOC_WR_LSB_FIRST: diff --git a/include/uapi/linux/spi/spidev.h b/include/uapi/linux/spi/spidev.h index 52d9ed01855f..dd5f21e75805 100644 --- a/include/uapi/linux/spi/spidev.h +++ b/include/uapi/linux/spi/spidev.h @@ -42,6 +42,10 @@ #define SPI_LOOP 0x20 #define SPI_NO_CS 0x40 #define SPI_READY 0x80 +#define SPI_TX_DUAL 0x100 +#define SPI_TX_QUAD 0x200 +#define SPI_RX_DUAL 0x400 +#define SPI_RX_QUAD 0x800 /*---------------------------------------------------------------------------*/ @@ -92,7 +96,9 @@ struct spi_ioc_transfer { __u16 delay_usecs; __u8 bits_per_word; __u8 cs_change; - __u32 pad; + __u8 tx_nbits; + __u8 rx_nbits; + __u16 pad; /* If the contents of 'struct spi_ioc_transfer' ever change * incompatibly, then the ioctl number (currently 0) must change; @@ -110,7 +116,7 @@ struct spi_ioc_transfer { #define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)]) -/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */ +/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) (limited to 8 bits) */ #define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8) #define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8) @@ -126,6 +132,10 @@ struct spi_ioc_transfer { #define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC, 4, __u32) #define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC, 4, __u32) +/* Read / Write of the SPI mode field */ +#define SPI_IOC_RD_MODE32 _IOR(SPI_IOC_MAGIC, 5, __u32) +#define SPI_IOC_WR_MODE32 _IOW(SPI_IOC_MAGIC, 5, __u32) + #endif /* SPIDEV_H */ From c2e78c34ef0bf4fa860b5fffc99c769d6ddaf52d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:18 +0100 Subject: [PATCH 121/201] spi: spidev_test: Add support for Dual/Quad SPI Transfers Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev_test.c | 43 ++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/Documentation/spi/spidev_test.c b/Documentation/spi/spidev_test.c index efd7385e907f..3a2f9d59edab 100644 --- a/Documentation/spi/spidev_test.c +++ b/Documentation/spi/spidev_test.c @@ -30,7 +30,7 @@ static void pabort(const char *s) } static const char *device = "/dev/spidev1.1"; -static uint8_t mode; +static uint32_t mode; static uint8_t bits = 8; static uint32_t speed = 500000; static uint16_t delay; @@ -57,6 +57,21 @@ static void transfer(int fd) .bits_per_word = bits, }; + if (mode & SPI_TX_QUAD) + tr.tx_nbits = 4; + else if (mode & SPI_TX_DUAL) + tr.tx_nbits = 2; + if (mode & SPI_RX_QUAD) + tr.rx_nbits = 4; + else if (mode & SPI_RX_DUAL) + tr.rx_nbits = 2; + if (!(mode & SPI_LOOP)) { + if (mode & (SPI_TX_QUAD | SPI_TX_DUAL)) + tr.rx_buf = 0; + else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL)) + tr.tx_buf = 0; + } + ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); if (ret < 1) pabort("can't send spi message"); @@ -83,7 +98,9 @@ static void print_usage(const char *prog) " -C --cs-high chip select active high\n" " -3 --3wire SI/SO signals shared\n" " -N --no-cs no chip select\n" - " -R --ready slave pulls low to pause\n"); + " -R --ready slave pulls low to pause\n" + " -2 --dual dual transfer\n" + " -4 --quad quad transfer\n"); exit(1); } @@ -103,11 +120,13 @@ static void parse_opts(int argc, char *argv[]) { "3wire", 0, 0, '3' }, { "no-cs", 0, 0, 'N' }, { "ready", 0, 0, 'R' }, + { "dual", 0, 0, '2' }, + { "quad", 0, 0, '4' }, { NULL, 0, 0, 0 }, }; int c; - c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR", lopts, NULL); + c = getopt_long(argc, argv, "D:s:d:b:lHOLC3NR24", lopts, NULL); if (c == -1) break; @@ -149,11 +168,23 @@ static void parse_opts(int argc, char *argv[]) case 'R': mode |= SPI_READY; break; + case '2': + mode |= SPI_TX_DUAL; + break; + case '4': + mode |= SPI_TX_QUAD; + break; default: print_usage(argv[0]); break; } } + if (mode & SPI_LOOP) { + if (mode & SPI_TX_DUAL) + mode |= SPI_RX_DUAL; + if (mode & SPI_TX_QUAD) + mode |= SPI_RX_QUAD; + } } int main(int argc, char *argv[]) @@ -170,11 +201,11 @@ int main(int argc, char *argv[]) /* * spi mode */ - ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); + ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode); if (ret == -1) pabort("can't set spi mode"); - ret = ioctl(fd, SPI_IOC_RD_MODE, &mode); + ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode); if (ret == -1) pabort("can't get spi mode"); @@ -200,7 +231,7 @@ int main(int argc, char *argv[]) if (ret == -1) pabort("can't get max speed hz"); - printf("spi mode: %d\n", mode); + printf("spi mode: 0x%x\n", mode); printf("bits per word: %d\n", bits); printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); From 4189a728ae26832edfabca300313e7fef2818d6f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:40:19 +0100 Subject: [PATCH 122/201] spi: spidev_fdx: Add support for Dual/Quad SPI Transfers Use SPI_IOC_RD_MODE32 to print the full SPI mode, now in hex. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- Documentation/spi/spidev_fdx.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Documentation/spi/spidev_fdx.c b/Documentation/spi/spidev_fdx.c index 36ec0774ca0b..0ea3e51292fc 100644 --- a/Documentation/spi/spidev_fdx.c +++ b/Documentation/spi/spidev_fdx.c @@ -78,10 +78,10 @@ static void do_msg(int fd, int len) static void dumpstat(const char *name, int fd) { - __u8 mode, lsb, bits; - __u32 speed; + __u8 lsb, bits; + __u32 mode, speed; - if (ioctl(fd, SPI_IOC_RD_MODE, &mode) < 0) { + if (ioctl(fd, SPI_IOC_RD_MODE32, &mode) < 0) { perror("SPI rd_mode"); return; } @@ -98,7 +98,7 @@ static void dumpstat(const char *name, int fd) return; } - printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n", + printf("%s: spi mode 0x%x, %d bits %sper word, %d Hz max\n", name, mode, bits, lsb ? "(lsb first) " : "", speed); } From 32d3b2d1ddeafe105ab6f738fba427242141194e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:08 +0100 Subject: [PATCH 123/201] spi: sh-msiof: Improve bindings Documentation: - Add missing "interrupt-parent", "#address-cells", "#size-cells", and "clocks" properties, - Add missing default values for "num-cs", "renesas,tx-fifo-size" and "renesas,rx-fifo-size", - Add a reference to the pinctrl documentation. Implementation: - As "num-cs" is marked optional, provide a sensible default. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/sh-msiof.txt | 24 +++++++++++++------ drivers/spi/spi-sh-msiof.c | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index e6222106ca36..eae3c8c9300e 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -1,12 +1,22 @@ Renesas MSIOF spi controller Required properties: -- compatible : "renesas,sh-msiof" for SuperH or - "renesas,sh-mobile-msiof" for SH Mobile series -- reg : Offset and length of the register set for the device -- interrupts : interrupt line used by MSIOF +- compatible : "renesas,sh-msiof" for SuperH, or + "renesas,sh-mobile-msiof" for SH Mobile series. +- reg : Offset and length of the register set for the device +- interrupt-parent : The phandle for the interrupt controller that + services interrupts for this device +- interrupts : Interrupt specifier +- #address-cells : Must be <1> +- #size-cells : Must be <0> Optional properties: -- num-cs : total number of chip-selects -- renesas,tx-fifo-size : Overrides the default tx fifo size given in words -- renesas,rx-fifo-size : Overrides the default rx fifo size given in words +- clocks : Must contain a reference to the functional clock. +- num-cs : Total number of chip-selects (default is 1) +- renesas,tx-fifo-size : Overrides the default tx fifo size given in words + (default is 64) +- renesas,rx-fifo-size : Overrides the default rx fifo size given in words + (default is 64) + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 6e2ba62ceb63..181efd049d12 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -664,7 +664,7 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) { struct sh_msiof_spi_info *info; struct device_node *np = dev->of_node; - u32 num_cs = 0; + u32 num_cs = 1; info = devm_kzalloc(dev, sizeof(struct sh_msiof_spi_info), GFP_KERNEL); if (!info) { From 50a7e23f53677918bf521b09ce9bb20fb87cd175 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:09 +0100 Subject: [PATCH 124/201] spi: sh-msiof: Move default FIFO sizes to device ID data As different variants of MSIOF have different FIFO sizes, move the default FIFO sizes to a new struct sh_msiof_chipdata, pointed to from the device ID data. [Moved ifdef to fix build -- broonie] Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 50 ++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 181efd049d12..38d6b70e9be2 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -30,11 +31,18 @@ #include + +struct sh_msiof_chipdata { + u16 tx_fifo_size; + u16 rx_fifo_size; +}; + struct sh_msiof_spi_priv { struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */ void __iomem *mapbase; struct clk *clk; struct platform_device *pdev; + const struct sh_msiof_chipdata *chipdata; struct sh_msiof_spi_info *info; struct completion done; unsigned long flags; @@ -113,10 +121,6 @@ struct sh_msiof_spi_priv { #define STR_REOF 0x00000080 /* Frame Reception End */ -#define DEFAULT_TX_FIFO_SIZE 64 -#define DEFAULT_RX_FIFO_SIZE 64 - - static u32 sh_msiof_read(struct sh_msiof_spi_priv *p, int reg_offs) { switch (reg_offs) { @@ -659,6 +663,18 @@ static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs, return 0; } +static const struct sh_msiof_chipdata sh_data = { + .tx_fifo_size = 64, + .rx_fifo_size = 64, +}; + +static const struct of_device_id sh_msiof_match[] = { + { .compatible = "renesas,sh-msiof", .data = &sh_data }, + { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, + {}, +}; +MODULE_DEVICE_TABLE(of, sh_msiof_match); + #ifdef CONFIG_OF static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev) { @@ -694,6 +710,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) { struct resource *r; struct spi_master *master; + const struct of_device_id *of_id; struct sh_msiof_spi_priv *p; int i; int ret; @@ -707,10 +724,15 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p = spi_master_get_devdata(master); platform_set_drvdata(pdev, p); - if (pdev->dev.of_node) + + of_id = of_match_device(sh_msiof_match, &pdev->dev); + if (of_id) { + p->chipdata = of_id->data; p->info = sh_msiof_spi_parse_dt(&pdev->dev); - else + } else { + p->chipdata = (const void *)pdev->id_entry->driver_data; p->info = dev_get_platdata(&pdev->dev); + } if (!p->info) { dev_err(&pdev->dev, "failed to obtain device info\n"); @@ -757,11 +779,9 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) p->pdev = pdev; pm_runtime_enable(&pdev->dev); - /* The standard version of MSIOF use 64 word FIFOs */ - p->tx_fifo_size = DEFAULT_TX_FIFO_SIZE; - p->rx_fifo_size = DEFAULT_RX_FIFO_SIZE; - /* Platform data may override FIFO sizes */ + p->tx_fifo_size = p->chipdata->tx_fifo_size; + p->rx_fifo_size = p->chipdata->rx_fifo_size; if (p->info->tx_fifo_override) p->tx_fifo_size = p->info->tx_fifo_override; if (p->info->rx_fifo_override) @@ -811,18 +831,16 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) return ret; } -#ifdef CONFIG_OF -static const struct of_device_id sh_msiof_match[] = { - { .compatible = "renesas,sh-msiof", }, - { .compatible = "renesas,sh-mobile-msiof", }, +static struct platform_device_id spi_driver_ids[] = { + { "spi_sh_msiof", (kernel_ulong_t)&sh_data }, {}, }; -MODULE_DEVICE_TABLE(of, sh_msiof_match); -#endif +MODULE_DEVICE_TABLE(platform, spi_driver_ids); static struct platform_driver sh_msiof_spi_drv = { .probe = sh_msiof_spi_probe, .remove = sh_msiof_spi_remove, + .id_table = spi_driver_ids, .driver = { .name = "spi_sh_msiof", .owner = THIS_MODULE, From beb74bb0875579c409778d853b8a050c124b3c79 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:10 +0100 Subject: [PATCH 125/201] spi: sh-msiof: Add support for R-Car H2 and M2 Add support for the MSIOF variant in the R-Car H2 (r8a7790) and M2 (r8a7791) SoCs. Binding documentation: - Add future-proof "renesas,msiof-" compatible values, - The default for "renesas,rx-fifo-size" is 256 on R-Car H2 and M2, - "renesas,tx-fifo-size" and "renesas,rx-fifo-size" are deprecated for soctype-specific bindings, - Add example bindings. Implementation: - MSIOF on R-Car H2 and M2 requires the transmission of dummy data if data is being received only (cfr. "Set SICTR.TSCKE to 1" and "Write dummy transmission data to SITFDR" in paragraph "Transmit and Receive Procedures" of the Hardware User's Manual). - As RX depends on TX, MSIOF on R-Car H2 and M2 also lacks the RSCR register (Receive Clock Select Register), and some bits in the RMDR1 (Receive Mode Register 1) and TMDR2 (Transmit Mode Register 2) registers. - Use the recently introduced SPI_MASTER_MUST_TX flag to enable support for dummy transmission in the SPI core, and to differentiate from other MSIOF implementations in code paths that need this. - New DT compatible values ("renesas,msiof-r8a7790" and "renesas,msiof-r8a7791") are added, as well as new platform device names ("spi_r8a7790_msiof" and "spi_r8a7791_msiof"). - The default RX FIFO size is 256 words on R-Car H2 and M2. This is loosely based on a set of patches from Takashi Yoshii . Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/sh-msiof.txt | 23 +++++++++++++++++-- drivers/spi/spi-sh-msiof.c | 23 ++++++++++++++++--- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index eae3c8c9300e..1f0cb33763a1 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -1,8 +1,13 @@ Renesas MSIOF spi controller Required properties: -- compatible : "renesas,sh-msiof" for SuperH, or +- compatible : "renesas,msiof-" for SoCs, + "renesas,sh-msiof" for SuperH, or "renesas,sh-mobile-msiof" for SH Mobile series. + Examples with soctypes are: + "renesas,msiof-sh7724" (SH) + "renesas,msiof-r8a7790" (R-Car H2) + "renesas,msiof-r8a7791" (R-Car M2) - reg : Offset and length of the register set for the device - interrupt-parent : The phandle for the interrupt controller that services interrupts for this device @@ -13,10 +18,24 @@ Required properties: Optional properties: - clocks : Must contain a reference to the functional clock. - num-cs : Total number of chip-selects (default is 1) + +Optional properties, deprecated for soctype-specific bindings: - renesas,tx-fifo-size : Overrides the default tx fifo size given in words (default is 64) - renesas,rx-fifo-size : Overrides the default rx fifo size given in words - (default is 64) + (default is 64, or 256 on R-Car H2 and M2) Pinctrl properties might be needed, too. See Documentation/devicetree/bindings/pinctrl/renesas,*. + +Example: + + msiof0: spi@e6e20000 { + compatible = "renesas,msiof-r8a7791"; + reg = <0 0xe6e20000 0 0x0064>; + interrupts = <0 156 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&mstp0_clks R8A7791_CLK_MSIOF0>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 38d6b70e9be2..e7f4797fa59d 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -35,6 +35,7 @@ struct sh_msiof_chipdata { u16 tx_fifo_size; u16 rx_fifo_size; + u16 master_flags; }; struct sh_msiof_spi_priv { @@ -215,7 +216,8 @@ static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p, k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1); sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr); - sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); + if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX)) + sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr); } static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, @@ -238,6 +240,10 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p, tmp |= !cs_high << MDR1_SYNCAC_SHIFT; tmp |= lsb_first << MDR1_BITLSB_SHIFT; sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON); + if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) { + /* These bits are reserved if RX needs TX */ + tmp &= ~0x0000ffff; + } sh_msiof_write(p, RMDR1, tmp); tmp = 0; @@ -258,7 +264,7 @@ static void sh_msiof_spi_set_mode_regs(struct sh_msiof_spi_priv *p, { u32 dr2 = MDR2_BITLEN1(bits) | MDR2_WDLEN1(words); - if (tx_buf) + if (tx_buf || (p->chipdata->master_flags & SPI_MASTER_MUST_TX)) sh_msiof_write(p, TMDR2, dr2); else sh_msiof_write(p, TMDR2, dr2 | MDR2_GRPMASK1); @@ -666,11 +672,20 @@ static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs, static const struct sh_msiof_chipdata sh_data = { .tx_fifo_size = 64, .rx_fifo_size = 64, + .master_flags = 0, +}; + +static const struct sh_msiof_chipdata r8a779x_data = { + .tx_fifo_size = 64, + .rx_fifo_size = 256, + .master_flags = SPI_MASTER_MUST_TX, }; static const struct of_device_id sh_msiof_match[] = { { .compatible = "renesas,sh-msiof", .data = &sh_data }, { .compatible = "renesas,sh-mobile-msiof", .data = &sh_data }, + { .compatible = "renesas,msiof-r8a7790", .data = &r8a779x_data }, + { .compatible = "renesas,msiof-r8a7791", .data = &r8a779x_data }, {}, }; MODULE_DEVICE_TABLE(of, sh_msiof_match); @@ -790,7 +805,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) /* init master and bitbang code */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; - master->flags = 0; + master->flags = p->chipdata->master_flags; master->bus_num = pdev->id; master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; @@ -833,6 +848,8 @@ static int sh_msiof_spi_remove(struct platform_device *pdev) static struct platform_device_id spi_driver_ids[] = { { "spi_sh_msiof", (kernel_ulong_t)&sh_data }, + { "spi_r8a7790_msiof", (kernel_ulong_t)&r8a779x_data }, + { "spi_r8a7791_msiof", (kernel_ulong_t)&r8a779x_data }, {}, }; MODULE_DEVICE_TABLE(platform, spi_driver_ids); From c833ff7304511805ce5a3378d1637e39e00e00ea Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:11 +0100 Subject: [PATCH 126/201] spi: sh-msiof: Move clock management to (un)prepare_message() Move clock management and pin configuration from the bitbang chipselect() method to the SPI core prepare_message() and unprepare_message() methods. As spi_master.{,un}prepare_message() is guaranteed to be called in matching pairs, the clock management synchronization is no longer needed. As sh_msiof_spi_set_pin_regs() is no longer called at spi_master.setup() time (through spi_bitbang_setup() and the spi_bitbang.chipselect() callback), we now have to take care of that ourselves. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 61 ++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index e7f4797fa59d..efeda03bbace 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -46,7 +46,6 @@ struct sh_msiof_spi_priv { const struct sh_msiof_chipdata *chipdata; struct sh_msiof_spi_info *info; struct completion done; - unsigned long flags; int tx_fifo_size; int rx_fifo_size; }; @@ -459,6 +458,7 @@ static int sh_msiof_spi_setup_transfer(struct spi_device *spi, static int sh_msiof_spi_setup(struct spi_device *spi) { struct device_node *np = spi->master->dev.of_node; + struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); if (!np) { /* @@ -468,12 +468,46 @@ static int sh_msiof_spi_setup(struct spi_device *spi) spi->cs_gpio = (uintptr_t)spi->controller_data; } + /* Configure pins before deasserting CS */ + sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), + !!(spi->mode & SPI_CPHA), + !!(spi->mode & SPI_3WIRE), + !!(spi->mode & SPI_LSB_FIRST), + !!(spi->mode & SPI_CS_HIGH)); + return spi_bitbang_setup(spi); } +static int sh_msiof_prepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); + const struct spi_device *spi = msg->spi; + + pm_runtime_get_sync(&p->pdev->dev); + clk_enable(p->clk); + + /* Configure pins before asserting CS */ + sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), + !!(spi->mode & SPI_CPHA), + !!(spi->mode & SPI_3WIRE), + !!(spi->mode & SPI_LSB_FIRST), + !!(spi->mode & SPI_CS_HIGH)); + return 0; +} + +static int sh_msiof_unprepare_message(struct spi_master *master, + struct spi_message *msg) +{ + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); + + clk_disable(p->clk); + pm_runtime_put(&p->pdev->dev); + return 0; +} + static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) { - struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); int value; /* chip select is active low unless SPI_CS_HIGH is set */ @@ -482,29 +516,8 @@ static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) else value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1; - if (is_on == BITBANG_CS_ACTIVE) { - if (!test_and_set_bit(0, &p->flags)) { - pm_runtime_get_sync(&p->pdev->dev); - clk_enable(p->clk); - } - - /* Configure pins before asserting CS */ - sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), - !!(spi->mode & SPI_CPHA), - !!(spi->mode & SPI_3WIRE), - !!(spi->mode & SPI_LSB_FIRST), - !!(spi->mode & SPI_CS_HIGH)); - } - if (spi->cs_gpio >= 0) gpio_set_value(spi->cs_gpio, value); - - if (is_on == BITBANG_CS_INACTIVE) { - if (test_and_clear_bit(0, &p->flags)) { - clk_disable(p->clk); - pm_runtime_put(&p->pdev->dev); - } - } } static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, @@ -811,6 +824,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->num_chipselect = p->info->num_chipselect; master->setup = sh_msiof_spi_setup; master->cleanup = spi_bitbang_cleanup; + master->prepare_message = sh_msiof_prepare_message; + master->unprepare_message = sh_msiof_unprepare_message; p->bitbang.master = master; p->bitbang.chipselect = sh_msiof_spi_chipselect; From 2416289c714343ea855e725d59d42668a9ab3cf6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:12 +0100 Subject: [PATCH 127/201] spi: sh-msiof: Convert to let spi core validate xfer->bits_per_word Set bits_per_word_mask so the spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index efeda03bbace..a0380b7c977f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -439,22 +439,6 @@ static u32 sh_msiof_spi_hz(struct spi_device *spi, struct spi_transfer *t) return hz; } -static int sh_msiof_spi_setup_transfer(struct spi_device *spi, - struct spi_transfer *t) -{ - int bits; - - /* noting to check hz values against since parent clock is disabled */ - - bits = sh_msiof_spi_bits(spi, t); - if (bits < 8) - return -EINVAL; - if (bits > 32) - return -EINVAL; - - return spi_bitbang_setup_transfer(spi, t); -} - static int sh_msiof_spi_setup(struct spi_device *spi) { struct device_node *np = spi->master->dev.of_node; @@ -826,10 +810,11 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->cleanup = spi_bitbang_cleanup; master->prepare_message = sh_msiof_prepare_message; master->unprepare_message = sh_msiof_unprepare_message; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); p->bitbang.master = master; p->bitbang.chipselect = sh_msiof_spi_chipselect; - p->bitbang.setup_transfer = sh_msiof_spi_setup_transfer; + p->bitbang.setup_transfer = spi_bitbang_setup_transfer; p->bitbang.txrx_bufs = sh_msiof_spi_txrx; p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word; p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word; From 1bd6363bc0c69ff6120b53daa35cf9459c3628ad Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 25 Feb 2014 11:21:13 +0100 Subject: [PATCH 128/201] spi: sh-msiof: Use core message handling instead of spi-bitbang The only remaining feature of spi-bitbang used by this driver is the chipselect() callback, which just does conditional GPIO. This is handled fine by the SPI core's spi_set_cs(), hence switch the driver to use the core message handling through our own transfer_one() method. As the (optional) GPIO CS is no longer deasserted at spi_master.setup() time (through spi_bitbang_setup() and the spi_bitbang.chipselect() callback), we now have to take care of that ourselves. Remove the call to spi_master_put() in sh_msiof_spi_remove(), as our SPI master is now registered using devm_spi_register_master() (spi_bitbang_start() uses the non-managed version). Signed-off-by: Geert Uytterhoeven Acked-by: Magnus Damm Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 1 - drivers/spi/spi-sh-msiof.c | 67 ++++++++++++-------------------------- 2 files changed, 20 insertions(+), 48 deletions(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..16f2987c29dc 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -416,7 +416,6 @@ config SPI_SH_MSIOF tristate "SuperH MSIOF SPI controller" depends on HAVE_CLK depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST - select SPI_BITBANG help SPI driver for SuperH and SH Mobile MSIOF blocks. diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index a0380b7c977f..db687011dc4f 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -27,7 +27,6 @@ #include #include -#include #include @@ -39,7 +38,6 @@ struct sh_msiof_chipdata { }; struct sh_msiof_spi_priv { - struct spi_bitbang bitbang; /* must be first for spi_bitbang.c */ void __iomem *mapbase; struct clk *clk; struct platform_device *pdev; @@ -459,7 +457,10 @@ static int sh_msiof_spi_setup(struct spi_device *spi) !!(spi->mode & SPI_LSB_FIRST), !!(spi->mode & SPI_CS_HIGH)); - return spi_bitbang_setup(spi); + if (spi->cs_gpio >= 0) + gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH)); + + return 0; } static int sh_msiof_prepare_message(struct spi_master *master, @@ -490,20 +491,6 @@ static int sh_msiof_unprepare_message(struct spi_master *master, return 0; } -static void sh_msiof_spi_chipselect(struct spi_device *spi, int is_on) -{ - int value; - - /* chip select is active low unless SPI_CS_HIGH is set */ - if (spi->mode & SPI_CS_HIGH) - value = (is_on == BITBANG_CS_ACTIVE) ? 1 : 0; - else - value = (is_on == BITBANG_CS_ACTIVE) ? 0 : 1; - - if (spi->cs_gpio >= 0) - gpio_set_value(spi->cs_gpio, value); -} - static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int), @@ -573,9 +560,11 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, return ret; } -static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) +static int sh_msiof_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { - struct sh_msiof_spi_priv *p = spi_master_get_devdata(spi->master); + struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int); void (*rx_fifo)(struct sh_msiof_spi_priv *, void *, int, int); int bits; @@ -656,13 +645,6 @@ static int sh_msiof_spi_txrx(struct spi_device *spi, struct spi_transfer *t) words -= n; } - return bytes_done; -} - -static u32 sh_msiof_spi_txrx_word(struct spi_device *spi, unsigned nsecs, - u32 word, u8 bits) -{ - BUG(); /* unused but needed by bitbang code */ return 0; } @@ -799,7 +781,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) if (p->info->rx_fifo_override) p->rx_fifo_size = p->info->rx_fifo_override; - /* init master and bitbang code */ + /* init master code */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; master->mode_bits |= SPI_LSB_FIRST | SPI_3WIRE; master->flags = p->chipdata->master_flags; @@ -807,24 +789,20 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->dev.of_node = pdev->dev.of_node; master->num_chipselect = p->info->num_chipselect; master->setup = sh_msiof_spi_setup; - master->cleanup = spi_bitbang_cleanup; master->prepare_message = sh_msiof_prepare_message; master->unprepare_message = sh_msiof_unprepare_message; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); + master->transfer_one = sh_msiof_transfer_one; - p->bitbang.master = master; - p->bitbang.chipselect = sh_msiof_spi_chipselect; - p->bitbang.setup_transfer = spi_bitbang_setup_transfer; - p->bitbang.txrx_bufs = sh_msiof_spi_txrx; - p->bitbang.txrx_word[SPI_MODE_0] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_1] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_2] = sh_msiof_spi_txrx_word; - p->bitbang.txrx_word[SPI_MODE_3] = sh_msiof_spi_txrx_word; + ret = devm_spi_register_master(&pdev->dev, master); + if (ret < 0) { + dev_err(&pdev->dev, "spi_register_master error.\n"); + goto err2; + } - ret = spi_bitbang_start(&p->bitbang); - if (ret == 0) - return 0; + return 0; + err2: pm_runtime_disable(&pdev->dev); clk_unprepare(p->clk); err1: @@ -835,15 +813,10 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) { struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); - int ret; - ret = spi_bitbang_stop(&p->bitbang); - if (!ret) { - pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); - spi_master_put(p->bitbang.master); - } - return ret; + pm_runtime_disable(&pdev->dev); + clk_unprepare(p->clk); + return 0; } static struct platform_device_id spi_driver_ids[] = { From 80d68ca5a52176a140e1daa527d0b698feb69c83 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Feb 2014 10:27:30 +0800 Subject: [PATCH 129/201] spi: sh-hspi: Remove hspi_cleanup function hspi_cleanup() is doing nothing except print a non-useful debug message, so remove it. Also remove unused hspi2info macro. Signed-off-by: Axel Lin Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index dbd2c44f95e9..dad800b9887f 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -46,8 +46,6 @@ /* SPSR */ #define RXFL (1 << 2) -#define hspi2info(h) (h->dev->platform_data) - struct hspi_priv { void __iomem *addr; struct spi_master *master; @@ -230,14 +228,6 @@ static int hspi_transfer_one_message(struct spi_master *master, return ret; } -static void hspi_cleanup(struct spi_device *spi) -{ - struct hspi_priv *hspi = spi_master_get_devdata(spi->master); - struct device *dev = hspi->dev; - - dev_dbg(dev, "%s cleanup\n", spi->modalias); -} - static int hspi_probe(struct platform_device *pdev) { struct resource *res; @@ -285,7 +275,6 @@ static int hspi_probe(struct platform_device *pdev) master->num_chipselect = 1; master->bus_num = pdev->id; - master->cleanup = hspi_cleanup; master->mode_bits = SPI_CPOL | SPI_CPHA; master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; From 7bdadd8d94a203c0bf02c0f128148e8be3e7f66a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:35:09 +0900 Subject: [PATCH 130/201] spi: txx9: Use devm_ioremap_resource() Use devm_ioremap_resource() in order to make the code simpler, and remove redundant return value check of platform_get_resource() because the value is checked by devm_ioremap_resource(). Signed-off-by: Jingoo Han Reviewed-by: Atsushi Nemoto Signed-off-by: Mark Brown --- drivers/spi/spi-txx9.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 523f13df52bb..5cfaafc368fc 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -358,13 +358,8 @@ static int txx9spi_probe(struct platform_device *dev) master->max_speed_hz = c->baseclk / (SPI_MIN_DIVIDER + 1); res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - goto exit_busy; - if (!devm_request_mem_region(&dev->dev, res->start, resource_size(res), - "spi_txx9")) - goto exit_busy; - c->membase = devm_ioremap(&dev->dev, res->start, resource_size(res)); - if (!c->membase) + c->membase = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(c->membase)) goto exit_busy; /* enter config mode */ From f8c717a567158cdd703b39118eec20cfffdcf585 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Feb 2014 19:19:43 +0800 Subject: [PATCH 131/201] spi: txx9: Let spi core handle validating transfer length spi core will handle validating transfer length since commit 4d94bd21b333 "spi: core: Validate length of the transfers in message". So remove the same checking in this driver. Signed-off-by: Axel Lin Reviewed-by: Atsushi Nemoto Signed-off-by: Mark Brown --- drivers/spi/spi-txx9.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c index 5cfaafc368fc..820b499816f8 100644 --- a/drivers/spi/spi-txx9.c +++ b/drivers/spi/spi-txx9.c @@ -306,12 +306,8 @@ static int txx9spi_transfer(struct spi_device *spi, struct spi_message *m) /* check each transfer's parameters */ list_for_each_entry(t, &m->transfers, transfer_list) { - u8 bits_per_word = t->bits_per_word; - if (!t->tx_buf && !t->rx_buf && t->len) return -EINVAL; - if (t->len & ((bits_per_word >> 3) - 1)) - return -EINVAL; } spin_lock_irqsave(&c->lock, flags); From cd2ac0c0cdc5b255489a2cfd388b2d3eda37e7a7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Feb 2014 19:16:57 +0800 Subject: [PATCH 132/201] spi: orion: Let spi core handle validating transfer length spi core will handle validating transfer length since commit 4d94bd21b333 "spi: core: Validate length of the transfers in message". So remove the same checking in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-orion.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index caaa53fc68cc..12ecb0762ccb 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -296,17 +296,6 @@ static int orion_spi_transfer_one_message(struct spi_master *master, goto msg_done; list_for_each_entry(t, &m->transfers, transfer_list) { - /* make sure buffer length is even when working in 16 - * bit mode*/ - if ((t->bits_per_word == 16) && (t->len & 1)) { - dev_err(&spi->dev, - "message rejected : " - "odd data length %d while in 16 bit mode\n", - t->len); - status = -EIO; - goto msg_done; - } - if (par_override || t->speed_hz || t->bits_per_word) { par_override = 1; status = orion_spi_setup_transfer(spi, t); From 5f59df79837bb809f3945613aba5519cd9755a53 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Sat, 1 Mar 2014 11:56:04 +0100 Subject: [PATCH 133/201] PM / runtime: Fetch runtime PM callbacks using a macro While fetching the proper runtime PM callback, we walk the hierarchy of device's power domains, subsystems and drivers. This is common for rpm_suspend(), rpm_idle() and rpm_resume(). Let's clean up the code by using a macro that handles this. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 78 ++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 72e00e66ecc5..ac495b1357fa 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -13,6 +13,42 @@ #include #include "power.h" +#define RPM_GET_CALLBACK(dev, cb) \ +({ \ + int (*__rpm_cb)(struct device *__d); \ + \ + if (dev->pm_domain) \ + __rpm_cb = dev->pm_domain->ops.cb; \ + else if (dev->type && dev->type->pm) \ + __rpm_cb = dev->type->pm->cb; \ + else if (dev->class && dev->class->pm) \ + __rpm_cb = dev->class->pm->cb; \ + else if (dev->bus && dev->bus->pm) \ + __rpm_cb = dev->bus->pm->cb; \ + else \ + __rpm_cb = NULL; \ + \ + if (!__rpm_cb && dev->driver && dev->driver->pm) \ + __rpm_cb = dev->driver->pm->cb; \ + \ + __rpm_cb; \ +}) + +static int (*rpm_get_suspend_cb(struct device *dev))(struct device *) +{ + return RPM_GET_CALLBACK(dev, runtime_suspend); +} + +static int (*rpm_get_resume_cb(struct device *dev))(struct device *) +{ + return RPM_GET_CALLBACK(dev, runtime_resume); +} + +static int (*rpm_get_idle_cb(struct device *dev))(struct device *) +{ + return RPM_GET_CALLBACK(dev, runtime_idle); +} + static int rpm_resume(struct device *dev, int rpmflags); static int rpm_suspend(struct device *dev, int rpmflags); @@ -310,19 +346,7 @@ static int rpm_idle(struct device *dev, int rpmflags) dev->power.idle_notification = true; - if (dev->pm_domain) - callback = dev->pm_domain->ops.runtime_idle; - else if (dev->type && dev->type->pm) - callback = dev->type->pm->runtime_idle; - else if (dev->class && dev->class->pm) - callback = dev->class->pm->runtime_idle; - else if (dev->bus && dev->bus->pm) - callback = dev->bus->pm->runtime_idle; - else - callback = NULL; - - if (!callback && dev->driver && dev->driver->pm) - callback = dev->driver->pm->runtime_idle; + callback = rpm_get_idle_cb(dev); if (callback) retval = __rpm_callback(callback, dev); @@ -492,19 +516,7 @@ static int rpm_suspend(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_SUSPENDING); - if (dev->pm_domain) - callback = dev->pm_domain->ops.runtime_suspend; - else if (dev->type && dev->type->pm) - callback = dev->type->pm->runtime_suspend; - else if (dev->class && dev->class->pm) - callback = dev->class->pm->runtime_suspend; - else if (dev->bus && dev->bus->pm) - callback = dev->bus->pm->runtime_suspend; - else - callback = NULL; - - if (!callback && dev->driver && dev->driver->pm) - callback = dev->driver->pm->runtime_suspend; + callback = rpm_get_suspend_cb(dev); retval = rpm_callback(callback, dev); if (retval) @@ -724,19 +736,7 @@ static int rpm_resume(struct device *dev, int rpmflags) __update_runtime_status(dev, RPM_RESUMING); - if (dev->pm_domain) - callback = dev->pm_domain->ops.runtime_resume; - else if (dev->type && dev->type->pm) - callback = dev->type->pm->runtime_resume; - else if (dev->class && dev->class->pm) - callback = dev->class->pm->runtime_resume; - else if (dev->bus && dev->bus->pm) - callback = dev->bus->pm->runtime_resume; - else - callback = NULL; - - if (!callback && dev->driver && dev->driver->pm) - callback = dev->driver->pm->runtime_resume; + callback = rpm_get_resume_cb(dev); retval = rpm_callback(callback, dev); if (retval) { From 37f204164dfb0186a0caf20bc3e3120080bcd788 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Sat, 1 Mar 2014 11:56:05 +0100 Subject: [PATCH 134/201] PM: Add pm_runtime_suspend|resume_force functions This patch provides two new runtime PM helper functions which intend to be used from system suspend/resume callbacks, to make sure devices are put into low power state during system suspend and brought back to full power at system resume. The prerequisite is to have all levels of a device's runtime PM callbacks to be defined through the SET_PM_RUNTIME_PM_OPS macro, which means these are available for CONFIG_PM. By using the new runtime PM helper functions especially the two scenarios below will be addressed. 1) The PM core prevents .runtime_suspend callbacks from being invoked during system suspend. That means even for a runtime PM centric subsystem and driver, the device needs to be put into low power state from a system suspend callback. Otherwise it may very well be left in full power state (runtime resumed) while the system is suspended. By using the new helper functions, we make sure to walk the hierarchy of a device's power domain, subsystem and driver. 2) Subsystems and drivers need to cope with all the combinations of CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME. The two new helper functions smothly addresses this. Signed-off-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- drivers/base/power/Makefile | 3 +- drivers/base/power/runtime.c | 84 ++++++++++++++++++++++++++++++++++++ include/linux/pm_runtime.h | 4 ++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/drivers/base/power/Makefile b/drivers/base/power/Makefile index 2e58ebb1f6c0..1cb8544598d5 100644 --- a/drivers/base/power/Makefile +++ b/drivers/base/power/Makefile @@ -1,6 +1,5 @@ -obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o +obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o -obj-$(CONFIG_PM_RUNTIME) += runtime.o obj-$(CONFIG_PM_TRACE_RTC) += trace.o obj-$(CONFIG_PM_OPP) += opp.o obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index ac495b1357fa..4776cf528d08 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -44,6 +44,7 @@ static int (*rpm_get_resume_cb(struct device *dev))(struct device *) return RPM_GET_CALLBACK(dev, runtime_resume); } +#ifdef CONFIG_PM_RUNTIME static int (*rpm_get_idle_cb(struct device *dev))(struct device *) { return RPM_GET_CALLBACK(dev, runtime_idle); @@ -1401,3 +1402,86 @@ void pm_runtime_remove(struct device *dev) if (dev->power.irq_safe && dev->parent) pm_runtime_put(dev->parent); } +#endif + +/** + * pm_runtime_force_suspend - Force a device into suspend state if needed. + * @dev: Device to suspend. + * + * Disable runtime PM so we safely can check the device's runtime PM status and + * if it is active, invoke it's .runtime_suspend callback to bring it into + * suspend state. Keep runtime PM disabled to preserve the state unless we + * encounter errors. + * + * Typically this function may be invoked from a system suspend callback to make + * sure the device is put into low power state. + */ +int pm_runtime_force_suspend(struct device *dev) +{ + int (*callback)(struct device *); + int ret = 0; + + pm_runtime_disable(dev); + + /* + * Note that pm_runtime_status_suspended() returns false while + * !CONFIG_PM_RUNTIME, which means the device will be put into low + * power state. + */ + if (pm_runtime_status_suspended(dev)) + return 0; + + callback = rpm_get_suspend_cb(dev); + + if (!callback) { + ret = -ENOSYS; + goto err; + } + + ret = callback(dev); + if (ret) + goto err; + + pm_runtime_set_suspended(dev); + return 0; +err: + pm_runtime_enable(dev); + return ret; +} +EXPORT_SYMBOL_GPL(pm_runtime_force_suspend); + +/** + * pm_runtime_force_resume - Force a device into resume state. + * @dev: Device to resume. + * + * Prior invoking this function we expect the user to have brought the device + * into low power state by a call to pm_runtime_force_suspend(). Here we reverse + * those actions and brings the device into full power. We update the runtime PM + * status and re-enables runtime PM. + * + * Typically this function may be invoked from a system resume callback to make + * sure the device is put into full power state. + */ +int pm_runtime_force_resume(struct device *dev) +{ + int (*callback)(struct device *); + int ret = 0; + + callback = rpm_get_resume_cb(dev); + + if (!callback) { + ret = -ENOSYS; + goto out; + } + + ret = callback(dev); + if (ret) + goto out; + + pm_runtime_set_active(dev); + pm_runtime_mark_last_busy(dev); +out: + pm_runtime_enable(dev); + return ret; +} +EXPORT_SYMBOL_GPL(pm_runtime_force_resume); diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 16c9a62fa1c0..2a5897a4afbc 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -26,9 +26,13 @@ #ifdef CONFIG_PM extern int pm_generic_runtime_suspend(struct device *dev); extern int pm_generic_runtime_resume(struct device *dev); +extern int pm_runtime_force_suspend(struct device *dev); +extern int pm_runtime_force_resume(struct device *dev); #else static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } +static inline int pm_runtime_force_suspend(struct device *dev) { return 0; } +static inline int pm_runtime_force_resume(struct device *dev) { return 0; } #endif #ifdef CONFIG_PM_RUNTIME From e428a420078eac26039b53af464355332809be52 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 23:01:50 +0800 Subject: [PATCH 135/201] spi: sh-hspi: Remove duplicate code to set default transfer speed In the implementation of __spi_validate(), spi core will use spi device's max speed as default transfer speed if it is not set for this transfer. So we can remove the same logic in hspi_hw_setup(). Signed-off-by: Axel Lin Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index dad800b9887f..180eecf72428 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -111,14 +111,9 @@ static void hspi_hw_setup(struct hspi_priv *hspi, { struct spi_device *spi = msg->spi; struct device *dev = hspi->dev; - u32 target_rate; u32 spcr, idiv_clk; u32 rate, best_rate, min, tmp; - target_rate = t ? t->speed_hz : 0; - if (!target_rate) - target_rate = spi->max_speed_hz; - /* * find best IDIV/CLKCx settings */ @@ -138,7 +133,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi, rate /= (((idiv_clk & 0x1F) + 1) * 2); /* save best settings */ - tmp = abs(target_rate - rate); + tmp = abs(t->speed_hz - rate); if (tmp < min) { min = tmp; spcr = idiv_clk; @@ -151,7 +146,7 @@ static void hspi_hw_setup(struct hspi_priv *hspi, if (spi->mode & SPI_CPOL) spcr |= 1 << 6; - dev_dbg(dev, "speed %d/%d\n", target_rate, best_rate); + dev_dbg(dev, "speed %d/%d\n", t->speed_hz, best_rate); hspi_write(hspi, SPCR, spcr); hspi_write(hspi, SPSR, 0x0); From b14158603288b9d898716b41f2f0acb7d49dad2c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 22:30:32 +0800 Subject: [PATCH 136/201] spi: sh-msiof: Kill sh_msiof_spi_bits and sh_msiof_spi_hz functions In the implementation of __spi_validate(), spi core will set transfer bits_per_word and max speed as spi device default if it is not set for this transfer. So we can remove the same implementation in this driver. Signed-off-by: Axel Lin Acked-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index db687011dc4f..3ffb8eed5ac5 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -417,26 +417,6 @@ static void sh_msiof_spi_read_fifo_s32u(struct sh_msiof_spi_priv *p, put_unaligned(swab32(sh_msiof_read(p, RFDR) >> fs), &buf_32[k]); } -static int sh_msiof_spi_bits(struct spi_device *spi, struct spi_transfer *t) -{ - int bits; - - bits = t ? t->bits_per_word : 0; - if (!bits) - bits = spi->bits_per_word; - return bits; -} - -static u32 sh_msiof_spi_hz(struct spi_device *spi, struct spi_transfer *t) -{ - u32 hz; - - hz = t ? t->speed_hz : 0; - if (!hz) - hz = spi->max_speed_hz; - return hz; -} - static int sh_msiof_spi_setup(struct spi_device *spi) { struct device_node *np = spi->master->dev.of_node; @@ -574,7 +554,7 @@ static int sh_msiof_transfer_one(struct spi_master *master, int n; bool swab; - bits = sh_msiof_spi_bits(spi, t); + bits = t->bits_per_word; if (bits <= 8 && t->len > 15 && !(t->len & 3)) { bits = 32; @@ -624,8 +604,7 @@ static int sh_msiof_transfer_one(struct spi_master *master, } /* setup clocks (clock already enabled in chipselect()) */ - sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), - sh_msiof_spi_hz(spi, t)); + sh_msiof_spi_set_clk_regs(p, clk_get_rate(p->clk), t->speed_hz); /* transfer in fifo sized chunks */ words = t->len / bytes_per_word; From eeb7139524d1851c29b5c02b3dcd6679299a104e Mon Sep 17 00:00:00 2001 From: Qipan Li Date: Sat, 1 Mar 2014 12:38:17 +0800 Subject: [PATCH 137/201] spi: sirf: provide a shortcut for spi command-data mode there are many SPI clients which use the following protocal: step 1: send command bytes to clients(rx buffer is empty) step 2: send data bytes to clients or receive data bytes from clients. SiRFprimaII provides a shortcut for this kind of SPI transfer. when tx buf is less or equal than 4 bytes and rx buf is null in a transfer, we think it as 'command' data and use hardware command register for the transfer. here we can save some CPU loading than doing both tx and rx for a normal transfer. Signed-off-by: Qipan Li Signed-off-by: Barry Song Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index dc962a17f373..a72b8f87a156 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -131,6 +131,8 @@ #define IS_DMA_VALID(x) (x && ALIGNED(x->tx_buf) && ALIGNED(x->rx_buf) && \ ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE)) +#define SIRFSOC_MAX_CMD_BYTES 4 + struct sirfsoc_spi { struct spi_bitbang bitbang; struct completion rx_done; @@ -161,6 +163,12 @@ struct sirfsoc_spi { void *dummypage; int word_width; /* in bytes */ + /* + * if tx size is not more than 4 and rx size is NULL, use + * command model + */ + bool tx_by_cmd; + int chipselect[0]; }; @@ -259,6 +267,12 @@ static irqreturn_t spi_sirfsoc_irq(int irq, void *dev_id) writel(spi_stat, sspi->base + SIRFSOC_SPI_INT_STATUS); + if (sspi->tx_by_cmd && (spi_stat & SIRFSOC_SPI_FRM_END)) { + complete(&sspi->tx_done); + writel(0x0, sspi->base + SIRFSOC_SPI_INT_EN); + return IRQ_HANDLED; + } + /* Error Conditions */ if (spi_stat & SIRFSOC_SPI_RX_OFLOW || spi_stat & SIRFSOC_SPI_TX_UFLOW) { @@ -309,6 +323,34 @@ static int spi_sirfsoc_transfer(struct spi_device *spi, struct spi_transfer *t) writel(SIRFSOC_SPI_INT_MASK_ALL, sspi->base + SIRFSOC_SPI_INT_STATUS); + /* + * fill tx_buf into command register and wait for its completion + */ + if (sspi->tx_by_cmd) { + u32 cmd; + memcpy(&cmd, sspi->tx, t->len); + + if (sspi->word_width == 1 && !(spi->mode & SPI_LSB_FIRST)) + cmd = cpu_to_be32(cmd) >> + ((SIRFSOC_MAX_CMD_BYTES - t->len) * 8); + if (sspi->word_width == 2 && t->len == 4 && + (!(spi->mode & SPI_LSB_FIRST))) + cmd = ((cmd & 0xffff) << 16) | (cmd >> 16); + + writel(cmd, sspi->base + SIRFSOC_SPI_CMD); + writel(SIRFSOC_SPI_FRM_END_INT_EN, + sspi->base + SIRFSOC_SPI_INT_EN); + writel(SIRFSOC_SPI_CMD_TX_EN, + sspi->base + SIRFSOC_SPI_TX_RX_EN); + + if (wait_for_completion_timeout(&sspi->tx_done, timeout) == 0) { + dev_err(&spi->dev, "transfer timeout\n"); + return 0; + } + + return t->len; + } + if (sspi->left_tx_word == 1) { writel(readl(sspi->base + SIRFSOC_SPI_CTRL) | SIRFSOC_SPI_ENA_AUTO_CLR, @@ -509,6 +551,14 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) writel(txfifo_ctrl, sspi->base + SIRFSOC_SPI_TXFIFO_CTRL); writel(rxfifo_ctrl, sspi->base + SIRFSOC_SPI_RXFIFO_CTRL); + if (t && t->tx_buf && !t->rx_buf && (t->len <= SIRFSOC_MAX_CMD_BYTES)) { + regval |= (SIRFSOC_SPI_CMD_BYTE_NUM((t->len - 1)) | + SIRFSOC_SPI_CMD_MODE); + sspi->tx_by_cmd = true; + } else { + regval &= ~SIRFSOC_SPI_CMD_MODE; + sspi->tx_by_cmd = false; + } writel(regval, sspi->base + SIRFSOC_SPI_CTRL); if (IS_DMA_VALID(t)) { From 0e6d873ac43c7452d33f7b57b8b91172ad0f78d7 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 19 Feb 2014 19:53:12 +0800 Subject: [PATCH 138/201] spi: atmel: Remove redundant list_empty checking This checking is already done in __spi_validate(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index b0842f751016..88bebf8cf0e5 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1221,9 +1221,6 @@ static int atmel_spi_transfer_one_message(struct spi_master *master, dev_dbg(&spi->dev, "new message %p submitted for %s\n", msg, dev_name(&spi->dev)); - if (unlikely(list_empty(&msg->transfers))) - return -EINVAL; - atmel_spi_lock(as); cs_activate(as, spi); From 790fc55a77bc041d613da087b3e03bdc59edcfa5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 15 Feb 2014 14:26:21 +0800 Subject: [PATCH 139/201] spi: omap-uwire: Convert to use bits_per_word_mask Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-omap-uwire.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 462ddd458217..95cc6948a2ba 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -99,7 +99,6 @@ struct uwire_spi { }; struct uwire_state { - unsigned bits_per_word; unsigned div1_idx; }; @@ -210,9 +209,8 @@ static void uwire_chipselect(struct spi_device *spi, int value) static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t) { - struct uwire_state *ust = spi->controller_state; unsigned len = t->len; - unsigned bits = ust->bits_per_word; + unsigned bits = t->bits_per_word ? : spi->bits_per_word; unsigned bytes; u16 val, w; int status = 0; @@ -322,7 +320,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) struct uwire_state *ust = spi->controller_state; struct uwire_spi *uwire; unsigned flags = 0; - unsigned bits; unsigned hz; unsigned long rate; int div1_idx; @@ -332,17 +329,6 @@ static int uwire_setup_transfer(struct spi_device *spi, struct spi_transfer *t) uwire = spi_master_get_devdata(spi->master); - bits = spi->bits_per_word; - if (t != NULL && t->bits_per_word) - bits = t->bits_per_word; - - if (bits > 16) { - pr_debug("%s: wordsize %d?\n", dev_name(&spi->dev), bits); - status = -ENODEV; - goto done; - } - ust->bits_per_word = bits; - /* mode 0..3, clock inverted separately; * standard nCS signaling; * don't treat DI=high as "not ready" @@ -509,7 +495,7 @@ static int uwire_probe(struct platform_device *pdev) /* the spi->mode bits understood by this driver: */ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; - + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); master->flags = SPI_MASTER_HALF_DUPLEX; master->bus_num = 2; /* "official" */ From 85fe414d3228bdecc52366692c6f70c750f687aa Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 19 Feb 2014 17:30:52 +0800 Subject: [PATCH 140/201] spi: octeon: Remove struct octeon_spi_setup usage Current code uses struct octeon_spi_setup to store max_speed_hz, chip_select and mode settings of current spi device. We can always get the same settings in octeon_spi_do_transfer() by msg->spi. So this patch removes struct octeon_spi_setup and octeon_spi_setup, octeon_spi_cleanup functions. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-octeon.c | 69 ++++------------------------------------ 1 file changed, 7 insertions(+), 62 deletions(-) diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index 31b41445a85e..a51458985ccf 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -33,12 +33,6 @@ struct octeon_spi { u64 cs_enax; }; -struct octeon_spi_setup { - u32 max_speed_hz; - u8 chip_select; - u8 mode; -}; - static void octeon_spi_wait_ready(struct octeon_spi *p) { union cvmx_mpi_sts mpi_sts; @@ -56,6 +50,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, struct spi_transfer *xfer, bool last_xfer) { + struct spi_device *spi = msg->spi; union cvmx_mpi_cfg mpi_cfg; union cvmx_mpi_tx mpi_tx; unsigned int clkdiv; @@ -67,16 +62,11 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, int len; int i; - struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi); - - speed_hz = msg_setup->max_speed_hz; - mode = msg_setup->mode; + mode = spi->mode; cpha = mode & SPI_CPHA; cpol = mode & SPI_CPOL; - if (xfer->speed_hz) - speed_hz = xfer->speed_hz; - + speed_hz = xfer->speed_hz ? : spi->max_speed_hz; if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ) speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; @@ -92,8 +82,8 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, mpi_cfg.s.cslate = cpha ? 1 : 0; mpi_cfg.s.enable = 1; - if (msg_setup->chip_select < 4) - p->cs_enax |= 1ull << (12 + msg_setup->chip_select); + if (spi->chip_select < 4) + p->cs_enax |= 1ull << (12 + spi->chip_select); mpi_cfg.u64 |= p->cs_enax; if (mpi_cfg.u64 != p->last_cfg) { @@ -113,7 +103,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); } mpi_tx.u64 = 0; - mpi_tx.s.csid = msg_setup->chip_select; + mpi_tx.s.csid = spi->chip_select; mpi_tx.s.leavecs = 1; mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; @@ -138,7 +128,7 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, } mpi_tx.u64 = 0; - mpi_tx.s.csid = msg_setup->chip_select; + mpi_tx.s.csid = spi->chip_select; if (last_xfer) mpi_tx.s.leavecs = xfer->cs_change; else @@ -168,15 +158,6 @@ static int octeon_spi_transfer_one_message(struct spi_master *master, int status = 0; struct spi_transfer *xfer; - /* - * We better have set the configuration via a call to .setup - * before we get here. - */ - if (spi_get_ctldata(msg->spi) == NULL) { - status = -EINVAL; - goto err; - } - list_for_each_entry(xfer, &msg->transfers, transfer_list) { bool last_xfer = list_is_last(&xfer->transfer_list, &msg->transfers); @@ -194,40 +175,6 @@ err: return status; } -static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi) -{ - struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL); - if (!setup) - return NULL; - - setup->max_speed_hz = spi->max_speed_hz; - setup->chip_select = spi->chip_select; - setup->mode = spi->mode; - return setup; -} - -static int octeon_spi_setup(struct spi_device *spi) -{ - struct octeon_spi_setup *new_setup; - struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); - - new_setup = octeon_spi_new_setup(spi); - if (!new_setup) - return -ENOMEM; - - spi_set_ctldata(spi, new_setup); - kfree(old_setup); - - return 0; -} - -static void octeon_spi_cleanup(struct spi_device *spi) -{ - struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); - spi_set_ctldata(spi, NULL); - kfree(old_setup); -} - static int octeon_spi_probe(struct platform_device *pdev) { struct resource *res_mem; @@ -265,8 +212,6 @@ static int octeon_spi_probe(struct platform_device *pdev) SPI_LSB_FIRST | SPI_3WIRE; - master->setup = octeon_spi_setup; - master->cleanup = octeon_spi_cleanup; master->transfer_one_message = octeon_spi_transfer_one_message; master->bits_per_word_mask = SPI_BPW_MASK(8); From 7984b5ca5c6245e332adcb8a8c2aefb2732b40bf Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 19 Feb 2014 17:34:47 +0800 Subject: [PATCH 141/201] spi: octeon: Convert to let spi core validate transfer speed Set master->max_speed_hz then spi core will handle checking transfer speed. The behavior is different from current code when the speed_hz is greater than the maximum transfer speed supported by the controller. Unless there is other good reason, I think we had better make the behavior consistent with what spi core does. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-octeon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c index a51458985ccf..1ed259449c7f 100644 --- a/drivers/spi/spi-octeon.c +++ b/drivers/spi/spi-octeon.c @@ -67,8 +67,6 @@ static int octeon_spi_do_transfer(struct octeon_spi *p, cpol = mode & SPI_CPOL; speed_hz = xfer->speed_hz ? : spi->max_speed_hz; - if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ) - speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz); @@ -214,6 +212,7 @@ static int octeon_spi_probe(struct platform_device *pdev) master->transfer_one_message = octeon_spi_transfer_one_message; master->bits_per_word_mask = SPI_BPW_MASK(8); + master->max_speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; master->dev.of_node = pdev->dev.of_node; err = devm_spi_register_master(&pdev->dev, master); From ad6f33d22c25e7340107a330e6de60bba57ecf52 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Feb 2014 19:57:19 +0800 Subject: [PATCH 142/201] spi: atmel: Let spi core handle validating transfer length spi core will handle validating transfer length since commit 4d94bd21b333 "spi: core: Validate length of the transfers in message". So remove the same checking in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 88bebf8cf0e5..4804586edd29 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1087,14 +1087,6 @@ static int atmel_spi_one_transfer(struct spi_master *master, } } - if (xfer->bits_per_word > 8) { - if (xfer->len % 2) { - dev_dbg(&spi->dev, - "buffer len should be 16 bits aligned\n"); - return -EINVAL; - } - } - /* * DMA map early, for performance (empties dcache ASAP) and * better fault reporting. From 765ee709eb40abf0c43c6d864ac6f01677b7fd5a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 20 Feb 2014 21:37:56 +0800 Subject: [PATCH 143/201] spi: dw: Convert to let spi core validate transfer speed Set master->max_speed_hz then spi core will handle checking transfer speed. So we can remove the same checking in this driver. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-dw.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index bf98d63d92b3..9e4a0aa7d341 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -439,12 +439,6 @@ static void pump_transfers(unsigned long data) if (transfer->speed_hz != speed) { speed = transfer->speed_hz; - if (speed > dws->max_freq) { - printk(KERN_ERR "MRST SPI0: unsupported" - "freq: %dHz\n", speed); - message->status = -EIO; - goto early_exit; - } /* clk_div doesn't support odd number */ clk_div = dws->max_freq / speed; @@ -809,6 +803,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->cleanup = dw_spi_cleanup; master->setup = dw_spi_setup; master->transfer = dw_spi_transfer; + master->max_speed_hz = dws->max_freq; /* Basic HW init */ spi_hw_init(dws); From ba47644d5b79914fe53b69c639902afce8ccfe7f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 22:25:10 +0800 Subject: [PATCH 144/201] spi: sun4i: Set bits_per_word_mask to only support 8 bits word length This controller only supports 8 bits word length. Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- drivers/spi/spi-sun4i.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-sun4i.c b/drivers/spi/spi-sun4i.c index 3f82705d0a27..d266a8702067 100644 --- a/drivers/spi/spi-sun4i.c +++ b/drivers/spi/spi-sun4i.c @@ -392,6 +392,7 @@ static int sun4i_spi_probe(struct platform_device *pdev) master->transfer_one = sun4i_spi_transfer_one; master->num_chipselect = 4; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + master->bits_per_word_mask = SPI_BPW_MASK(8); master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; From 743a46b89a59abcc6566d9d90b1f28bfa666702e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 22:25:58 +0800 Subject: [PATCH 145/201] spi: sun6i: Set bits_per_word_mask to only support 8 bits word length This controller only supports 8 bits word length. Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- drivers/spi/spi-sun6i.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 4b9ec08022fe..b3e3498a7e6f 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -391,6 +391,7 @@ static int sun6i_spi_probe(struct platform_device *pdev) master->transfer_one = sun6i_spi_transfer_one; master->num_chipselect = 4; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST; + master->bits_per_word_mask = SPI_BPW_MASK(8); master->dev.of_node = pdev->dev.of_node; master->auto_runtime_pm = true; From af348519e4a41eac8eae82cf3dcaeb6c1b008113 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 22:48:41 +0800 Subject: [PATCH 146/201] spi: xcomm: Remove duplicate code to set default bits_per_word and max speed In the implementation of __spi_validate(), spi core will set transfer bits_per_word and max speed as spi device default if it is not set for this transfer. So we can remove the same logic in spi_xcomm_setup_transfer(). Also remove a redundant code to initialize is_first variable. Signed-off-by: Axel Lin Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- drivers/spi/spi-xcomm.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-xcomm.c b/drivers/spi/spi-xcomm.c index 24c40b13dab1..2505b7e1232a 100644 --- a/drivers/spi/spi-xcomm.c +++ b/drivers/spi/spi-xcomm.c @@ -74,15 +74,13 @@ static void spi_xcomm_chipselect(struct spi_xcomm *spi_xcomm, static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, struct spi_device *spi, struct spi_transfer *t, unsigned int *settings) { - unsigned int speed; - if (t->len > 62) return -EINVAL; - speed = t->speed_hz ? t->speed_hz : spi->max_speed_hz; + if (t->speed_hz != spi_xcomm->current_speed) { + unsigned int divider; - if (speed != spi_xcomm->current_speed) { - unsigned int divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, speed); + divider = DIV_ROUND_UP(SPI_XCOMM_CLOCK, t->speed_hz); if (divider >= 64) *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_64; else if (divider >= 16) @@ -90,7 +88,7 @@ static int spi_xcomm_setup_transfer(struct spi_xcomm *spi_xcomm, else *settings |= SPI_XCOMM_SETTINGS_CLOCK_DIV_4; - spi_xcomm->current_speed = speed; + spi_xcomm->current_speed = t->speed_hz; } if (spi->mode & SPI_CPOL) @@ -148,8 +146,6 @@ static int spi_xcomm_transfer_one(struct spi_master *master, int status = 0; bool is_last; - is_first = true; - spi_xcomm_chipselect(spi_xcomm, spi, true); list_for_each_entry(t, &msg->transfers, transfer_list) { From 6ea312936d68b557766dafa9a3c4617e14ffa076 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Fri, 28 Feb 2014 23:03:16 +0900 Subject: [PATCH 147/201] spi: core: make zero length transfer valid again Zero length transfer becomes invalid since "spi: core: Validate length of the transfers in message" commit, but it should be valid to support an odd device, for example, which requires long delay between chipselect and the first transfer, etc. Signed-off-by: Atsushi Nemoto Tested-by: Thierry Reding Signed-off-by: Mark Brown --- drivers/spi/spi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index d5ee965fb285..9d1405440223 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1617,7 +1617,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) { struct spi_master *master = spi->master; struct spi_transfer *xfer; - int w_size, n_words; + int w_size; if (list_empty(&message->transfers)) return -EINVAL; @@ -1680,9 +1680,8 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) else w_size = 4; - n_words = xfer->len / w_size; /* No partial transfers accepted */ - if (!n_words || xfer->len % w_size) + if (xfer->len % w_size) return -EINVAL; if (xfer->speed_hz && master->min_speed_hz && From 5bdfd491a01955727a6b2382534ec7760174863e Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 5 Mar 2014 09:58:49 +0800 Subject: [PATCH 148/201] spi: atmel: adopt pinctrl support Amend the spi atmel pin controller to optionally take a pin control handle and set the state of the pins to: - "default" on boot, resume and before performing an spitransfer - "sleep" on suspend() This should make it possible to optimize energy usage for the pins both for the suspend/resume cycle Signed-off-by: Wenyou Yang Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 4804586edd29..c83b0c620fa1 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -26,6 +26,7 @@ #include #include +#include /* SPI register offsets */ #define SPI_CR 0x0000 @@ -1292,6 +1293,9 @@ static int atmel_spi_probe(struct platform_device *pdev) struct spi_master *master; struct atmel_spi *as; + /* Select default pin state */ + pinctrl_pm_select_default_state(&pdev->dev); + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) return -ENXIO; @@ -1446,6 +1450,9 @@ static int atmel_spi_suspend(struct device *dev) struct atmel_spi *as = spi_master_get_devdata(master); clk_disable_unprepare(as->clk); + + pinctrl_pm_select_sleep_state(dev); + return 0; } @@ -1454,6 +1461,8 @@ static int atmel_spi_resume(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct atmel_spi *as = spi_master_get_devdata(master); + pinctrl_pm_select_default_state(dev); + clk_prepare_enable(as->clk); return 0; } From 8bd313453736d8efa82afee01c899774b29362ac Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Feb 2014 09:54:25 +0800 Subject: [PATCH 149/201] spi: coldfire-qspi: Remove unused dev field from struct mcfqspi Also remove unused *res variable in mcfqspi_remove(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index cabed8f9119e..e35294239034 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -77,8 +77,6 @@ struct mcfqspi { struct mcfqspi_cs_control *cs_control; wait_queue_head_t waitq; - - struct device *dev; }; static void mcfqspi_wr_qmr(struct mcfqspi *mcfqspi, u16 val) @@ -436,7 +434,6 @@ static int mcfqspi_probe(struct platform_device *pdev) } init_waitqueue_head(&mcfqspi->waitq); - mcfqspi->dev = &pdev->dev; master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); @@ -451,7 +448,7 @@ static int mcfqspi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "spi_register_master failed\n"); goto fail2; } - pm_runtime_enable(mcfqspi->dev); + pm_runtime_enable(&pdev->dev); dev_info(&pdev->dev, "Coldfire QSPI bus driver\n"); @@ -473,9 +470,8 @@ static int mcfqspi_remove(struct platform_device *pdev) { struct spi_master *master = platform_get_drvdata(pdev); struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pm_runtime_disable(mcfqspi->dev); + pm_runtime_disable(&pdev->dev); /* disable the hardware (set the baud rate to 0) */ mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR); From 3531b717d05273e45efd2ab7903ea013aaec3fea Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 14 Feb 2014 09:55:55 +0800 Subject: [PATCH 150/201] spi: coldfire-qspi: Use core message handling Convert to use default implementation of transfer_one_message(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 83 ++++++++++++++------------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index e35294239034..8d594c6704ad 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -298,58 +298,44 @@ static void mcfqspi_transfer_msg16(struct mcfqspi *mcfqspi, unsigned count, } } -static int mcfqspi_transfer_one_message(struct spi_master *master, - struct spi_message *msg) +static void mcfqspi_set_cs(struct spi_device *spi, bool enable) +{ + struct mcfqspi *mcfqspi = spi_master_get_devdata(spi->master); + bool cs_high = spi->mode & SPI_CS_HIGH; + + if (enable) + mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high); + else + mcfqspi_cs_deselect(mcfqspi, spi->chip_select, cs_high); +} + +static int mcfqspi_transfer_one(struct spi_master *master, + struct spi_device *spi, + struct spi_transfer *t) { struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - struct spi_device *spi = msg->spi; - struct spi_transfer *t; - int status = 0; + u16 qmr = MCFQSPI_QMR_MSTR; - list_for_each_entry(t, &msg->transfers, transfer_list) { - bool cs_high = spi->mode & SPI_CS_HIGH; - u16 qmr = MCFQSPI_QMR_MSTR; + qmr |= t->bits_per_word << 10; + if (spi->mode & SPI_CPHA) + qmr |= MCFQSPI_QMR_CPHA; + if (spi->mode & SPI_CPOL) + qmr |= MCFQSPI_QMR_CPOL; + if (t->speed_hz) + qmr |= mcfqspi_qmr_baud(t->speed_hz); + else + qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); + mcfqspi_wr_qmr(mcfqspi, qmr); - qmr |= t->bits_per_word << 10; - if (spi->mode & SPI_CPHA) - qmr |= MCFQSPI_QMR_CPHA; - if (spi->mode & SPI_CPOL) - qmr |= MCFQSPI_QMR_CPOL; - if (t->speed_hz) - qmr |= mcfqspi_qmr_baud(t->speed_hz); - else - qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); - mcfqspi_wr_qmr(mcfqspi, qmr); - - mcfqspi_cs_select(mcfqspi, spi->chip_select, cs_high); - - mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); - if (t->bits_per_word == 8) - mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, - t->rx_buf); - else - mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf, - t->rx_buf); - mcfqspi_wr_qir(mcfqspi, 0); - - if (t->delay_usecs) - udelay(t->delay_usecs); - if (t->cs_change) { - if (!list_is_last(&t->transfer_list, &msg->transfers)) - mcfqspi_cs_deselect(mcfqspi, spi->chip_select, - cs_high); - } else { - if (list_is_last(&t->transfer_list, &msg->transfers)) - mcfqspi_cs_deselect(mcfqspi, spi->chip_select, - cs_high); - } - msg->actual_length += t->len; - } - msg->status = status; - spi_finalize_current_message(master); - - return status; + mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); + if (t->bits_per_word == 8) + mcfqspi_transfer_msg8(mcfqspi, t->len, t->tx_buf, t->rx_buf); + else + mcfqspi_transfer_msg16(mcfqspi, t->len / 2, t->tx_buf, + t->rx_buf); + mcfqspi_wr_qir(mcfqspi, 0); + return 0; } static int mcfqspi_setup(struct spi_device *spi) @@ -438,7 +424,8 @@ static int mcfqspi_probe(struct platform_device *pdev) master->mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); master->setup = mcfqspi_setup; - master->transfer_one_message = mcfqspi_transfer_one_message; + master->set_cs = mcfqspi_set_cs; + master->transfer_one = mcfqspi_transfer_one; master->auto_runtime_pm = true; platform_set_drvdata(pdev, master); From 31804f638ef213f78f4a5ee896c4226ba55ab415 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:27:10 +0900 Subject: [PATCH 151/201] spi: omap-100k: fix spacing coding style issue Fix the following checkpatch issues. ERROR: space prohibited after that open parenthesis '(' ERROR: space required before the open parenthesis '(' ERROR: trailing statements should be on next line ERROR: space required after that ',' (ctx:VxV) ERROR: spaces required around that '-=' (ctx:VxV) WARNING: sizeof *cs should be sizeof(*cs) Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index 3b8b36a144b4..c9e228242643 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -128,7 +128,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) } spi100k_enable_clock(master); - writew( data , spi100k->base + SPI_TX_MSB); + writew(data , spi100k->base + SPI_TX_MSB); writew(SPI_CTRL_SEN(0) | SPI_CTRL_WORD_SIZE(len) | @@ -136,7 +136,8 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) spi100k->base + SPI_CTRL); /* Wait for bit ack send change */ - while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE); + while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_WE) != SPI_STATUS_WE) + ; udelay(1000); spi100k_disable_clock(master); @@ -144,7 +145,7 @@ static void spi100k_write_data(struct spi_master *master, int len, int data) static int spi100k_read_data(struct spi_master *master, int len) { - int dataH,dataL; + int dataH, dataL; struct omap1_spi100k *spi100k = spi_master_get_devdata(master); /* Always do at least 16 bits */ @@ -157,7 +158,8 @@ static int spi100k_read_data(struct spi_master *master, int len) SPI_CTRL_RD, spi100k->base + SPI_CTRL); - while((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD); + while ((readw(spi100k->base + SPI_STATUS) & SPI_STATUS_RD) != SPI_STATUS_RD) + ; udelay(1000); dataL = readw(spi100k->base + SPI_RX_LSB); @@ -208,12 +210,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { - c-=1; + c -= 1; if (xfer->tx_buf != NULL) spi100k_write_data(spi->master, word_len, *tx++); if (xfer->rx_buf != NULL) *rx++ = spi100k_read_data(spi->master, word_len); - } while(c); + } while (c); } else if (word_len <= 16) { u16 *rx; const u16 *tx; @@ -221,12 +223,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { - c-=2; + c -= 2; if (xfer->tx_buf != NULL) - spi100k_write_data(spi->master,word_len, *tx++); + spi100k_write_data(spi->master, word_len, *tx++); if (xfer->rx_buf != NULL) - *rx++ = spi100k_read_data(spi->master,word_len); - } while(c); + *rx++ = spi100k_read_data(spi->master, word_len); + } while (c); } else if (word_len <= 32) { u32 *rx; const u32 *tx; @@ -234,12 +236,12 @@ omap1_spi100k_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) rx = xfer->rx_buf; tx = xfer->tx_buf; do { - c-=4; + c -= 4; if (xfer->tx_buf != NULL) - spi100k_write_data(spi->master,word_len, *tx); + spi100k_write_data(spi->master, word_len, *tx); if (xfer->rx_buf != NULL) - *rx = spi100k_read_data(spi->master,word_len); - } while(c); + *rx = spi100k_read_data(spi->master, word_len); + } while (c); } return count - c; } @@ -281,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi) spi100k = spi_master_get_devdata(spi->master); if (!cs) { - cs = kzalloc(sizeof *cs, GFP_KERNEL); + cs = kzalloc(sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; cs->base = spi100k->base + spi->chip_select * 0x14; @@ -398,14 +400,14 @@ static int omap1_spi100k_probe(struct platform_device *pdev) if (!pdev->id) return -EINVAL; - master = spi_alloc_master(&pdev->dev, sizeof *spi100k); + master = spi_alloc_master(&pdev->dev, sizeof(*spi100k)); if (master == NULL) { dev_dbg(&pdev->dev, "master allocation failed\n"); return -ENOMEM; } if (pdev->id != -1) - master->bus_num = pdev->id; + master->bus_num = pdev->id; master->setup = omap1_spi100k_setup; master->transfer_one_message = omap1_spi100k_transfer_one_message; From 1480916ebd6fc9c54da5e9e09cf342a061063e39 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:28:24 +0900 Subject: [PATCH 152/201] spi: bcm63xx-hsspi: Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx-hsspi.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-bcm63xx-hsspi.c b/drivers/spi/spi-bcm63xx-hsspi.c index b528f9fc8bc0..13bbce349ed9 100644 --- a/drivers/spi/spi-bcm63xx-hsspi.c +++ b/drivers/spi/spi-bcm63xx-hsspi.c @@ -453,9 +453,8 @@ static int bcm63xx_hsspi_resume(struct device *dev) } #endif -static const struct dev_pm_ops bcm63xx_hsspi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(bcm63xx_hsspi_suspend, bcm63xx_hsspi_resume) -}; +static SIMPLE_DEV_PM_OPS(bcm63xx_hsspi_pm_ops, bcm63xx_hsspi_suspend, + bcm63xx_hsspi_resume); static struct platform_driver bcm63xx_hsspi_driver = { .driver = { From ba811addff3d29d1ea9861dbfc06e8ef80714f94 Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Wed, 26 Feb 2014 10:30:14 +0900 Subject: [PATCH 153/201] spi: fsl-dspi: Use SIMPLE_DEV_PM_OPS macro Use SIMPLE_DEV_PM_OPS macro in order to make the code simpler. Signed-off-by: Jingoo Han Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 42ede0d796a7..7f0dddb21833 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -437,9 +437,7 @@ static int dspi_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ -static const struct dev_pm_ops dspi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(dspi_suspend, dspi_resume) -}; +static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); static struct regmap_config dspi_regmap_config = { .reg_bits = 32, From 736198b0486c8d5032456de0813515d954df978a Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Sat, 1 Mar 2014 11:56:06 +0100 Subject: [PATCH 154/201] spi: pl022: Let runtime PM callbacks be available for CONFIG_PM Convert to the SET_PM_RUNTIME_PM macro while defining the runtime PM callbacks. This means the callbacks becomes available for both CONFIG_PM_SLEEP and CONFIG_PM_RUNTIME, which is needed to handle the combinations of these scenarios. Signed-off-by: Ulf Hansson Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 74a072924b65..6dfcabf74728 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2277,7 +2277,7 @@ pl022_remove(struct amba_device *adev) return 0; } -#if defined(CONFIG_SUSPEND) || defined(CONFIG_PM_RUNTIME) +#ifdef CONFIG_PM /* * These two functions are used from both suspend/resume and * the runtime counterparts to handle external resources like @@ -2343,7 +2343,7 @@ static int pl022_resume(struct device *dev) } #endif /* CONFIG_PM */ -#ifdef CONFIG_PM_RUNTIME +#ifdef CONFIG_PM static int pl022_runtime_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); @@ -2363,7 +2363,7 @@ static int pl022_runtime_resume(struct device *dev) static const struct dev_pm_ops pl022_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume) - SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) + SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) }; static struct vendor_data vendor_arm = { From 84a5dc41f64faadb79cde600b130c8cbd7e21977 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Sat, 1 Mar 2014 11:56:07 +0100 Subject: [PATCH 155/201] spi: pl022: Don't ignore power domain and amba bus at system suspend Previously only the resources controlled by the driver were put into low power state at system suspend. Both the amba bus and a potential power domain were ignored. Moreover, while putting the device into low power state we first brought it back to full power, but for no particular reason. To handle both issues above, use pm_runtime_force_suspend|resume() from the system suspend|resume callbacks. Signed-off-by: Ulf Hansson Signed-off-by: Mark Brown --- drivers/spi/spi-pl022.c | 54 ++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c index 6dfcabf74728..d37e840944d6 100644 --- a/drivers/spi/spi-pl022.c +++ b/drivers/spi/spi-pl022.c @@ -2277,35 +2277,7 @@ pl022_remove(struct amba_device *adev) return 0; } -#ifdef CONFIG_PM -/* - * These two functions are used from both suspend/resume and - * the runtime counterparts to handle external resources like - * clocks, pins and regulators when going to sleep. - */ -static void pl022_suspend_resources(struct pl022 *pl022, bool runtime) -{ - clk_disable_unprepare(pl022->clk); - - if (runtime) - pinctrl_pm_select_idle_state(&pl022->adev->dev); - else - pinctrl_pm_select_sleep_state(&pl022->adev->dev); -} - -static void pl022_resume_resources(struct pl022 *pl022, bool runtime) -{ - /* First go to the default state */ - pinctrl_pm_select_default_state(&pl022->adev->dev); - if (!runtime) - /* Then let's idle the pins until the next transfer happens */ - pinctrl_pm_select_idle_state(&pl022->adev->dev); - - clk_prepare_enable(pl022->clk); -} -#endif - -#ifdef CONFIG_SUSPEND +#ifdef CONFIG_PM_SLEEP static int pl022_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); @@ -2317,8 +2289,13 @@ static int pl022_suspend(struct device *dev) return ret; } - pm_runtime_get_sync(dev); - pl022_suspend_resources(pl022, false); + ret = pm_runtime_force_suspend(dev); + if (ret) { + spi_master_resume(pl022->master); + return ret; + } + + pinctrl_pm_select_sleep_state(dev); dev_dbg(dev, "suspended\n"); return 0; @@ -2329,8 +2306,9 @@ static int pl022_resume(struct device *dev) struct pl022 *pl022 = dev_get_drvdata(dev); int ret; - pl022_resume_resources(pl022, false); - pm_runtime_put(dev); + ret = pm_runtime_force_resume(dev); + if (ret) + dev_err(dev, "problem resuming\n"); /* Start the queue running */ ret = spi_master_resume(pl022->master); @@ -2341,14 +2319,16 @@ static int pl022_resume(struct device *dev) return ret; } -#endif /* CONFIG_PM */ +#endif #ifdef CONFIG_PM static int pl022_runtime_suspend(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - pl022_suspend_resources(pl022, true); + clk_disable_unprepare(pl022->clk); + pinctrl_pm_select_idle_state(dev); + return 0; } @@ -2356,7 +2336,9 @@ static int pl022_runtime_resume(struct device *dev) { struct pl022 *pl022 = dev_get_drvdata(dev); - pl022_resume_resources(pl022, true); + pinctrl_pm_select_default_state(dev); + clk_prepare_enable(pl022->clk); + return 0; } #endif From 380603712072145785f19040b9791f4f6cde414e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Mar 2014 15:17:23 +0800 Subject: [PATCH 156/201] spi: s3c24xx: Add missing spi_master_{resume,suspend} calls to PM callbacks This is required since commit 2025172e3280 "spi/bitbang: Use core message pump". spi-bitbang now uses core message pump, so it needs to call spi_master_suspend/ spi_master_resume to start/stop the queue while suspend/resume. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-s3c24xx.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index f1ffbfa6acef..b7f5c349a3c0 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -634,6 +634,11 @@ static int s3c24xx_spi_remove(struct platform_device *dev) static int s3c24xx_spi_suspend(struct device *dev) { struct s3c24xx_spi *hw = dev_get_drvdata(dev); + int ret; + + ret = spi_master_suspend(hw->master); + if (ret) + return ret; if (hw->pdata && hw->pdata->gpio_setup) hw->pdata->gpio_setup(hw->pdata, 0); @@ -647,7 +652,7 @@ static int s3c24xx_spi_resume(struct device *dev) struct s3c24xx_spi *hw = dev_get_drvdata(dev); s3c24xx_spi_initialsetup(hw); - return 0; + return spi_master_resume(hw->master); } static const struct dev_pm_ops s3c24xx_spi_pmops = { From 9304f51e5f3e1365860968bce168d904f3e31bd3 Mon Sep 17 00:00:00 2001 From: Sourav Poddar Date: Mon, 10 Mar 2014 16:00:42 +0530 Subject: [PATCH 157/201] spi/ti-qspi: Fix return from mmap path mmap resource requirement is only for memory mapped operations. If the user does not populate mmap resource, dont call return, instead we go on for normal spi mode operations. Signed-off-by: Sourav Poddar Signed-off-by: Mark Brown --- drivers/spi/spi-ti-qspi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c index 3d09265b5133..66a4029ee035 100644 --- a/drivers/spi/spi-ti-qspi.c +++ b/drivers/spi/spi-ti-qspi.c @@ -461,7 +461,6 @@ static int ti_qspi_probe(struct platform_device *pdev) if (res_mmap == NULL) { dev_err(&pdev->dev, "memory mapped resource not required\n"); - return -ENODEV; } } From 2aa237f4a1a72813f9684a0ce6e48288e75de479 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 26 Feb 2014 09:47:55 +0800 Subject: [PATCH 158/201] spi: coldfire-qspi: Enable clock before calling spi_master_resume This ensures clock has been enabled before calling spi_master_resume(). while at it, also add checking return value of spi_master_suspend and spi_master_resume because they may fail. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 8d594c6704ad..94d817523d5f 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -473,8 +473,11 @@ static int mcfqspi_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct mcfqspi *mcfqspi = spi_master_get_devdata(master); + int ret; - spi_master_suspend(master); + ret = spi_master_suspend(master); + if (ret) + return ret; clk_disable(mcfqspi->clk); @@ -486,11 +489,9 @@ static int mcfqspi_resume(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct mcfqspi *mcfqspi = spi_master_get_devdata(master); - spi_master_resume(master); - clk_enable(mcfqspi->clk); - return 0; + return spi_master_resume(master); } #endif From fcba212de9bdf1016d981c355df29ab169da8eae Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 4 Mar 2014 12:59:53 +0800 Subject: [PATCH 159/201] spi: clps711x: Provide label argument for devm_gpio_request The label argument was removed by commit 989847967cd762 spi: clps711x: Use devm_gpio_request(), add it back. This makes it easier to know the gpio usage in /sys/kernel/debug/gpio. Also remove unnecessary gpio_is_valid() checking, devm_gpio_request() returns error if the requested gpio is invalid. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index eda7472ceefa..a5938abacfb0 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -159,14 +159,10 @@ static int spi_clps711x_probe(struct platform_device *pdev) for (i = 0; i < master->num_chipselect; i++) { master->cs_gpios[i] = pdata->chipselect[i]; - if (!gpio_is_valid(master->cs_gpios[i])) { - dev_err(&pdev->dev, "Invalid CS GPIO %i\n", i); - ret = -EINVAL; - goto err_out; - } - if (devm_gpio_request(&pdev->dev, master->cs_gpios[i], NULL)) { + ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i], + DRIVER_NAME); + if (ret) { dev_err(&pdev->dev, "Can't get CS GPIO %i\n", i); - ret = -EINVAL; goto err_out; } } From 2271cf124a2763b7252887814a7fc8a844767e8f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 9 Mar 2014 14:11:10 +0800 Subject: [PATCH 160/201] spi: coldfire-qspi: Prevent NULL pointer dereference If pdata->cs_control is NULL, we will hit NULL pointer dereference in mcfqspi_cs_select() and mcfqspi_cs_deselect(). Thus add NULL test for pdata->cs_control in probe(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 94d817523d5f..6d78f96bdc55 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -133,13 +133,13 @@ static void mcfqspi_cs_deselect(struct mcfqspi *mcfqspi, u8 chip_select, static int mcfqspi_cs_setup(struct mcfqspi *mcfqspi) { - return (mcfqspi->cs_control && mcfqspi->cs_control->setup) ? + return (mcfqspi->cs_control->setup) ? mcfqspi->cs_control->setup(mcfqspi->cs_control) : 0; } static void mcfqspi_cs_teardown(struct mcfqspi *mcfqspi) { - if (mcfqspi->cs_control && mcfqspi->cs_control->teardown) + if (mcfqspi->cs_control->teardown) mcfqspi->cs_control->teardown(mcfqspi->cs_control); } @@ -372,6 +372,11 @@ static int mcfqspi_probe(struct platform_device *pdev) return -ENOENT; } + if (!pdata->cs_control) { + dev_dbg(&pdev->dev, "pdata->cs_control is NULL\n"); + return -EINVAL; + } + master = spi_alloc_master(&pdev->dev, sizeof(*mcfqspi)); if (master == NULL) { dev_dbg(&pdev->dev, "spi_alloc_master failed\n"); From f9ee821ebc5e58ff5da08d625ea4e2d74b221317 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:43:26 +0100 Subject: [PATCH 161/201] spi: sh-msiof: Remove "renesas,msiof-sh7724" from bindings It's not implemented in the driver, so it's a bad example. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/sh-msiof.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/sh-msiof.txt b/Documentation/devicetree/bindings/spi/sh-msiof.txt index 1f0cb33763a1..f24baf3b6cc1 100644 --- a/Documentation/devicetree/bindings/spi/sh-msiof.txt +++ b/Documentation/devicetree/bindings/spi/sh-msiof.txt @@ -5,7 +5,6 @@ Required properties: "renesas,sh-msiof" for SuperH, or "renesas,sh-mobile-msiof" for SH Mobile series. Examples with soctypes are: - "renesas,msiof-sh7724" (SH) "renesas,msiof-r8a7790" (R-Car H2) "renesas,msiof-r8a7791" (R-Car M2) - reg : Offset and length of the register set for the device From c3003ce144fe0279e4299030b1cfad6f4b39116a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:40:51 +0100 Subject: [PATCH 162/201] spi: sh-spi: Improve bindings - Add future-proof "renesas,hspi-" compatible values, - Add missing "interrupt-parent", "#address-cells", and "#size-cells" properties, - Add reference to pinctrl documentation, - Add example bindings. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/sh-hspi.txt | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/sh-hspi.txt b/Documentation/devicetree/bindings/spi/sh-hspi.txt index 30b57b1c8a13..319bad4af875 100644 --- a/Documentation/devicetree/bindings/spi/sh-hspi.txt +++ b/Documentation/devicetree/bindings/spi/sh-hspi.txt @@ -1,7 +1,29 @@ Renesas HSPI. Required properties: -- compatible : "renesas,hspi" -- reg : Offset and length of the register set for the device -- interrupts : interrupt line used by HSPI +- compatible : "renesas,hspi-", "renesas,hspi" as fallback. + Examples with soctypes are: + - "renesas,hspi-r8a7778" (R-Car M1) + - "renesas,hspi-r8a7779" (R-Car H1) +- reg : Offset and length of the register set for the device +- interrupt-parent : The phandle for the interrupt controller that + services interrupts for this device +- interrupts : Interrupt specifier +- #address-cells : Must be <1> +- #size-cells : Must be <0> + +Pinctrl properties might be needed, too. See +Documentation/devicetree/bindings/pinctrl/renesas,*. + +Example: + + hspi0: spi@fffc7000 { + compatible = "renesas,hspi-r8a7778", "renesas,hspi"; + reg = <0xfffc7000 0x18>; + interrupt-parent = <&gic>; + interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; From 3abf0edd2c16326727326c35704ab9cad0529eda Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:59:10 +0100 Subject: [PATCH 163/201] spi: sh-hspi: Add missing call to pm_runtime_disable() in failure path Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-hspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c index 180eecf72428..89cfedf6d21a 100644 --- a/drivers/spi/spi-sh-hspi.c +++ b/drivers/spi/spi-sh-hspi.c @@ -279,11 +279,13 @@ static int hspi_probe(struct platform_device *pdev) ret = devm_spi_register_master(&pdev->dev, master); if (ret < 0) { dev_err(&pdev->dev, "spi_register_master error.\n"); - goto error1; + goto error2; } return 0; + error2: + pm_runtime_disable(&pdev->dev); error1: clk_put(clk); error0: From e2a0ba547ba31cd7b217cc948d93e4edc78cbcb1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:59:11 +0100 Subject: [PATCH 164/201] spi: sh-msiof: Convert to spi core auto_runtime_pm framework Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-msiof.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c index 3ffb8eed5ac5..b6b013a2f397 100644 --- a/drivers/spi/spi-sh-msiof.c +++ b/drivers/spi/spi-sh-msiof.c @@ -449,9 +449,6 @@ static int sh_msiof_prepare_message(struct spi_master *master, struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); const struct spi_device *spi = msg->spi; - pm_runtime_get_sync(&p->pdev->dev); - clk_enable(p->clk); - /* Configure pins before asserting CS */ sh_msiof_spi_set_pin_regs(p, !!(spi->mode & SPI_CPOL), !!(spi->mode & SPI_CPHA), @@ -461,16 +458,6 @@ static int sh_msiof_prepare_message(struct spi_master *master, return 0; } -static int sh_msiof_unprepare_message(struct spi_master *master, - struct spi_message *msg) -{ - struct sh_msiof_spi_priv *p = spi_master_get_devdata(master); - - clk_disable(p->clk); - pm_runtime_put(&p->pdev->dev); - return 0; -} - static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p, void (*tx_fifo)(struct sh_msiof_spi_priv *, const void *, int, int), @@ -743,12 +730,6 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) goto err1; } - ret = clk_prepare(p->clk); - if (ret < 0) { - dev_err(&pdev->dev, "unable to prepare clock\n"); - goto err1; - } - p->pdev = pdev; pm_runtime_enable(&pdev->dev); @@ -769,8 +750,8 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) master->num_chipselect = p->info->num_chipselect; master->setup = sh_msiof_spi_setup; master->prepare_message = sh_msiof_prepare_message; - master->unprepare_message = sh_msiof_unprepare_message; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 32); + master->auto_runtime_pm = true; master->transfer_one = sh_msiof_transfer_one; ret = devm_spi_register_master(&pdev->dev, master); @@ -783,7 +764,6 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) err2: pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); err1: spi_master_put(master); return ret; @@ -791,10 +771,7 @@ static int sh_msiof_spi_probe(struct platform_device *pdev) static int sh_msiof_spi_remove(struct platform_device *pdev) { - struct sh_msiof_spi_priv *p = platform_get_drvdata(pdev); - pm_runtime_disable(&pdev->dev); - clk_unprepare(p->clk); return 0; } From 490c97747d5dc77dfb5826e2823b41d8b2ef7ecc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 10:59:12 +0100 Subject: [PATCH 165/201] spi: rspi: Add runtime PM support, using spi core auto_runtime_pm Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-rspi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 92bec7e91046..1fb0ad213324 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -1111,7 +1112,7 @@ static int rspi_remove(struct platform_device *pdev) struct rspi_data *rspi = platform_get_drvdata(pdev); rspi_release_dma(rspi); - clk_disable_unprepare(rspi->clk); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1242,16 +1243,13 @@ static int rspi_probe(struct platform_device *pdev) goto error1; } - ret = clk_prepare_enable(rspi->clk); - if (ret < 0) { - dev_err(&pdev->dev, "unable to prepare/enable clock\n"); - goto error1; - } + pm_runtime_enable(&pdev->dev); init_waitqueue_head(&rspi->wait); master->bus_num = pdev->id; master->setup = rspi_setup; + master->auto_runtime_pm = true; master->transfer_one = ops->transfer_one; master->prepare_message = rspi_prepare_message; master->unprepare_message = rspi_unprepare_message; @@ -1312,7 +1310,7 @@ static int rspi_probe(struct platform_device *pdev) error3: rspi_release_dma(rspi); error2: - clk_disable_unprepare(rspi->clk); + pm_runtime_disable(&pdev->dev); error1: spi_master_put(master); From f9f4cbde587335515acaaef9e23028fc0a616292 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 12 Mar 2014 18:35:23 +0800 Subject: [PATCH 166/201] spi: efm32: Clean up non-DT paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a DT-only driver, so remove all non-DT paths. of_gpio_named_count() may fail, thus also add checking it's return value. efm32_spi_probe_dt() never fails, make it return void. Signed-off-by: Axel Lin Acked-by: Uwe Kleine-König Signed-off-by: Mark Brown --- drivers/spi/spi-efm32.c | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index 7199d2fd2b0b..0512fedf1f13 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -287,16 +287,13 @@ static u32 efm32_spi_get_configured_location(struct efm32_spi_ddata *ddata) return (reg & REG_ROUTE_LOCATION__MASK) >> __ffs(REG_ROUTE_LOCATION__MASK); } -static int efm32_spi_probe_dt(struct platform_device *pdev, +static void efm32_spi_probe_dt(struct platform_device *pdev, struct spi_master *master, struct efm32_spi_ddata *ddata) { struct device_node *np = pdev->dev.of_node; u32 location; int ret; - if (!np) - return 1; - ret = of_property_read_u32(np, "location", &location); if (!ret) { dev_dbg(&pdev->dev, "using location %u\n", location); @@ -308,7 +305,6 @@ static int efm32_spi_probe_dt(struct platform_device *pdev, } ddata->pdata.location = location; - return 0; } static int efm32_spi_probe(struct platform_device *pdev) @@ -318,9 +314,14 @@ static int efm32_spi_probe(struct platform_device *pdev) int ret; struct spi_master *master; struct device_node *np = pdev->dev.of_node; - unsigned int num_cs, i; + int num_cs, i; + + if (!np) + return -EINVAL; num_cs = of_gpio_named_count(np, "cs-gpios"); + if (num_cs < 0) + return num_cs; master = spi_alloc_master(&pdev->dev, sizeof(*ddata) + num_cs * sizeof(unsigned)); @@ -411,23 +412,7 @@ static int efm32_spi_probe(struct platform_device *pdev) goto err; } - ret = efm32_spi_probe_dt(pdev, master, ddata); - if (ret > 0) { - /* not created by device tree */ - const struct efm32_spi_pdata *pdata = - dev_get_platdata(&pdev->dev); - - if (pdata) - ddata->pdata = *pdata; - else - ddata->pdata.location = - efm32_spi_get_configured_location(ddata); - - master->bus_num = pdev->id; - - } else if (ret < 0) { - goto err_disable_clk; - } + efm32_spi_probe_dt(pdev, master, ddata); efm32_spi_write32(ddata, 0, REG_IEN); efm32_spi_write32(ddata, REG_ROUTE_TXPEN | REG_ROUTE_RXPEN | From 6840cc29f2bcc9a06a7245d17e0e2f38fbc20df0 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 12 Mar 2014 21:55:24 +0400 Subject: [PATCH 167/201] spi: add xtfpga SPI controller driver This simple SPI master controller is built into xtfpga bitstreams. It always transfers 16 bit words in SPI mode 0, automatically asserting CS on transfer start and deasserting on end. Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 13 +++ drivers/spi/Makefile | 1 + drivers/spi/spi-xtensa-xtfpga.c | 170 ++++++++++++++++++++++++++++++++ 3 files changed, 184 insertions(+) create mode 100644 drivers/spi/spi-xtensa-xtfpga.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..c87475db0f79 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -520,6 +520,19 @@ config SPI_XILINX Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" +config SPI_XTENSA_XTFPGA + tristate "Xtensa SPI controller for xtfpga" + depends on XTENSA && XTENSA_PLATFORM_XTFPGA + select SPI_BITBANG + help + SPI driver for xtfpga SPI master controller. + + This simple SPI master controller is built into xtfpga bitstreams + and is used to control daughterboard audio codec. It always transfers + 16 bit words in SPI mode 0, automatically asserting CS on transfer + start and deasserting on end. + + config SPI_NUC900 tristate "Nuvoton NUC900 series SPI" depends on ARCH_W90X900 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 95af48d2d360..5379adee0a77 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -79,3 +79,4 @@ obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o obj-$(CONFIG_SPI_TXX9) += spi-txx9.o obj-$(CONFIG_SPI_XCOMM) += spi-xcomm.o obj-$(CONFIG_SPI_XILINX) += spi-xilinx.o +obj-$(CONFIG_SPI_XTENSA_XTFPGA) += spi-xtensa-xtfpga.o diff --git a/drivers/spi/spi-xtensa-xtfpga.c b/drivers/spi/spi-xtensa-xtfpga.c new file mode 100644 index 000000000000..41e158187f9d --- /dev/null +++ b/drivers/spi/spi-xtensa-xtfpga.c @@ -0,0 +1,170 @@ +/* + * Xtensa xtfpga SPI controller driver + * + * Copyright (c) 2014 Cadence Design Systems Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define XTFPGA_SPI_NAME "xtfpga_spi" + +#define XTFPGA_SPI_START 0x0 +#define XTFPGA_SPI_BUSY 0x4 +#define XTFPGA_SPI_DATA 0x8 + +#define BUSY_WAIT_US 100 + +struct xtfpga_spi { + struct spi_bitbang bitbang; + void __iomem *regs; + u32 data; + unsigned data_sz; +}; + +static inline void xtfpga_spi_write32(const struct xtfpga_spi *spi, + unsigned addr, u32 val) +{ + iowrite32(val, spi->regs + addr); +} + +static inline unsigned int xtfpga_spi_read32(const struct xtfpga_spi *spi, + unsigned addr) +{ + return ioread32(spi->regs + addr); +} + +static inline void xtfpga_spi_wait_busy(struct xtfpga_spi *xspi) +{ + unsigned i; + for (i = 0; xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY) && + i < BUSY_WAIT_US; ++i) + udelay(1); + WARN_ON_ONCE(i == BUSY_WAIT_US); +} + +static u32 xtfpga_spi_txrx_word(struct spi_device *spi, unsigned nsecs, + u32 v, u8 bits) +{ + struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master); + + xspi->data = (xspi->data << bits) | (v & GENMASK(bits - 1, 0)); + xspi->data_sz += bits; + if (xspi->data_sz >= 16) { + xtfpga_spi_write32(xspi, XTFPGA_SPI_DATA, + xspi->data >> (xspi->data_sz - 16)); + xspi->data_sz -= 16; + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 1); + xtfpga_spi_wait_busy(xspi); + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0); + } + + return 0; +} + +static void xtfpga_spi_chipselect(struct spi_device *spi, int is_on) +{ + struct xtfpga_spi *xspi = spi_master_get_devdata(spi->master); + + WARN_ON(xspi->data_sz != 0); + xspi->data_sz = 0; +} + +static int xtfpga_spi_probe(struct platform_device *pdev) +{ + struct xtfpga_spi *xspi; + struct resource *mem; + int ret; + struct spi_master *master; + + master = spi_alloc_master(&pdev->dev, sizeof(struct xtfpga_spi)); + if (!master) + return -ENOMEM; + + master->flags = SPI_MASTER_NO_RX; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + master->bus_num = pdev->dev.id; + master->dev.of_node = pdev->dev.of_node; + + xspi = spi_master_get_devdata(master); + xspi->bitbang.master = master; + xspi->bitbang.chipselect = xtfpga_spi_chipselect; + xspi->bitbang.txrx_word[SPI_MODE_0] = xtfpga_spi_txrx_word; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!mem) { + dev_err(&pdev->dev, "No memory resource\n"); + ret = -ENODEV; + goto err; + } + xspi->regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(xspi->regs)) { + ret = PTR_ERR(xspi->regs); + goto err; + } + + xtfpga_spi_write32(xspi, XTFPGA_SPI_START, 0); + usleep_range(1000, 2000); + if (xtfpga_spi_read32(xspi, XTFPGA_SPI_BUSY)) { + dev_err(&pdev->dev, "Device stuck in busy state\n"); + ret = -EBUSY; + goto err; + } + + ret = spi_bitbang_start(&xspi->bitbang); + if (ret < 0) { + dev_err(&pdev->dev, "spi_bitbang_start failed\n"); + goto err; + } + + platform_set_drvdata(pdev, master); + return 0; +err: + spi_master_put(master); + return ret; +} + +static int xtfpga_spi_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct xtfpga_spi *xspi = spi_master_get_devdata(master); + + spi_bitbang_stop(&xspi->bitbang); + spi_master_put(master); + + return 0; +} + +MODULE_ALIAS("platform:" XTFPGA_SPI_NAME); + +#ifdef CONFIG_OF +static const struct of_device_id xtfpga_spi_of_match[] = { + { .compatible = "cdns,xtfpga-spi", }, + {} +}; +MODULE_DEVICE_TABLE(of, xtfpga_spi_of_match); +#endif + +static struct platform_driver xtfpga_spi_driver = { + .probe = xtfpga_spi_probe, + .remove = xtfpga_spi_remove, + .driver = { + .name = XTFPGA_SPI_NAME, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(xtfpga_spi_of_match), + }, +}; +module_platform_driver(xtfpga_spi_driver); + +MODULE_AUTHOR("Max Filippov "); +MODULE_DESCRIPTION("xtensa xtfpga SPI driver"); +MODULE_LICENSE("GPL"); From 27a89b9f0dc7c98b5c28882656d1044434ba28f1 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 12 Mar 2014 21:55:25 +0400 Subject: [PATCH 168/201] spi/xtensa-xtfpga: add DT binding documentation Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- .../devicetree/bindings/spi/spi-xtensa-xtfpga.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt diff --git a/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt new file mode 100644 index 000000000000..b6ebe2bc7041 --- /dev/null +++ b/Documentation/devicetree/bindings/spi/spi-xtensa-xtfpga.txt @@ -0,0 +1,9 @@ +Cadence Xtensa XTFPGA platform SPI controller. + +This simple SPI master controller is built into xtfpga bitstreams and is used +to control daughterboard audio codec. + +Required properties: +- compatible: should be "cdns,xtfpga-spi". +- reg: physical base address of the controller and length of memory mapped + region. From f620e4b81685e95b43894e85f443dfe252fb17b6 Mon Sep 17 00:00:00 2001 From: Max Filippov Date: Wed, 12 Mar 2014 21:55:26 +0400 Subject: [PATCH 169/201] MAINTAINERS: add xtfpga platform section This section will list xtfpga platform-specific drivers. Signed-off-by: Max Filippov Signed-off-by: Mark Brown --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b2cf5cfb4d29..f34b325cfd77 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9740,6 +9740,12 @@ L: linux-serial@vger.kernel.org S: Maintained F: drivers/tty/serial/uartlite.c +XTENSA XTFPGA PLATFORM SUPPORT +M: Max Filippov +L: linux-xtensa@linux-xtensa.org +S: Maintained +F: drivers/spi/spi-xtensa-xtfpga.c + YAM DRIVER FOR AX.25 M: Jean-Paul Roubelat L: linux-hams@vger.kernel.org From 09e99bca8324c3335794b86802486bb5191861d5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Feb 2014 18:39:33 +0800 Subject: [PATCH 170/201] spi: sc18is602: Convert to let spi core validate transfer speed Set master->max_speed_hz and master->min_speed_hz then spi core will handle checking transfer speed. So we can remove the same checking in this driver. This patch also remove testing if hz is 0 because spi->max_speed_hz will be default set to master->min_speed_hz if it was not set. So the transfer speed will never set to 0. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sc18is602.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c index 7fba10bba3b0..237f2e7a7179 100644 --- a/drivers/spi/spi-sc18is602.c +++ b/drivers/spi/spi-sc18is602.c @@ -183,17 +183,9 @@ static int sc18is602_setup_transfer(struct sc18is602 *hw, u32 hz, u8 mode) static int sc18is602_check_transfer(struct spi_device *spi, struct spi_transfer *t, int tlen) { - uint32_t hz; - if (t && t->len + tlen > SC18IS602_BUFSIZ) return -EINVAL; - hz = spi->max_speed_hz; - if (t && t->speed_hz) - hz = t->speed_hz; - if (hz == 0) - return -EINVAL; - return 0; } @@ -207,14 +199,13 @@ static int sc18is602_transfer_one(struct spi_master *master, hw->tlen = 0; list_for_each_entry(t, &m->transfers, transfer_list) { - u32 hz = t->speed_hz ? : spi->max_speed_hz; bool do_transfer; status = sc18is602_check_transfer(spi, t, hw->tlen); if (status < 0) break; - status = sc18is602_setup_transfer(hw, hz, spi->mode); + status = sc18is602_setup_transfer(hw, t->speed_hz, spi->mode); if (status < 0) break; @@ -305,6 +296,8 @@ static int sc18is602_probe(struct i2c_client *client, master->setup = sc18is602_setup; master->transfer_one_message = sc18is602_transfer_one; master->dev.of_node = np; + master->min_speed_hz = hw->freq / 128; + master->max_speed_hz = hw->freq / 4; error = devm_spi_register_master(dev, master); if (error) From bed890b4310b1d3b33c88fb83e216a8182e8bbad Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 2 Mar 2014 23:24:18 +0800 Subject: [PATCH 171/201] spi: clps711x: Remove duplicate code to set default bits_per_word and max speed In the implementation of __spi_validate(), spi core will set transfer bits_per_word and max speed as spi device default if it is not set for this transfer. So we can remove the same logic in spi_clps711x_setup_xfer() and spi_clps711x_transfer_one(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index a5938abacfb0..ab010c05dc5a 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -45,17 +45,16 @@ static int spi_clps711x_setup(struct spi_device *spi) static void spi_clps711x_setup_xfer(struct spi_device *spi, struct spi_transfer *xfer) { - u32 speed = xfer->speed_hz ? : spi->max_speed_hz; struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master); /* Setup SPI frequency divider */ - if (!speed || (speed >= hw->max_speed_hz)) + if (!xfer->speed_hz || (xfer->speed_hz >= hw->max_speed_hz)) clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | SYSCON1_ADCKSEL(3), SYSCON1); - else if (speed >= (hw->max_speed_hz / 2)) + else if (xfer->speed_hz >= (hw->max_speed_hz / 2)) clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | SYSCON1_ADCKSEL(2), SYSCON1); - else if (speed >= (hw->max_speed_hz / 8)) + else if (xfer->speed_hz >= (hw->max_speed_hz / 8)) clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | SYSCON1_ADCKSEL(1), SYSCON1); else @@ -87,7 +86,7 @@ static int spi_clps711x_transfer_one(struct spi_master *master, spi_clps711x_setup_xfer(spi, xfer); hw->len = xfer->len; - hw->bpw = xfer->bits_per_word ? : spi->bits_per_word; + hw->bpw = xfer->bits_per_word; hw->tx_buf = (u8 *)xfer->tx_buf; hw->rx_buf = (u8 *)xfer->rx_buf; From 14c48ab2d9be451ff51783cfb9996428b145e878 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Mar 2014 13:34:21 +0800 Subject: [PATCH 172/201] spi: oc-tiny: Remove unneeded NULL checking for hw->bitbang.master We already has NULL test for master after calling spi_alloc_master(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-oc-tiny.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-oc-tiny.c b/drivers/spi/spi-oc-tiny.c index f7c896e2981e..4fd2981b3605 100644 --- a/drivers/spi/spi-oc-tiny.c +++ b/drivers/spi/spi-oc-tiny.c @@ -267,8 +267,6 @@ static int tiny_spi_probe(struct platform_device *pdev) /* setup the state for the bitbang driver */ hw->bitbang.master = master; - if (!hw->bitbang.master) - return err; hw->bitbang.setup_transfer = tiny_spi_setup_transfer; hw->bitbang.chipselect = tiny_spi_chipselect; hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs; From 72bb79d042375586c4ad8def57d7932064d76090 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Mar 2014 13:37:00 +0800 Subject: [PATCH 173/201] spi: altera: Use bits_per_word_mask This driver does not work for bits_per_word greater than 16. Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-altera.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index 5d7deaf62867..aa33b56b7a92 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -214,6 +214,7 @@ static int altera_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = 16; master->mode_bits = SPI_CS_HIGH; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); hw = spi_master_get_devdata(master); platform_set_drvdata(pdev, hw); From a82ba3a318dd5eaf1f3dcbc335f81770d557a4fc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 5 Mar 2014 15:19:09 +0800 Subject: [PATCH 174/201] spi: sirf: Add missing spi_master_{resume,suspend} calls to PM callbacks This is required since commit 2025172e3280 "spi/bitbang: Use core message pump". spi-bitbang now uses core message pump, so it needs to call spi_master_suspend/ spi_master_resume to stop/start the queue while suspend/resume. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-sirf.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index a72b8f87a156..1a77ad52812f 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c @@ -748,6 +748,11 @@ static int spi_sirfsoc_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); struct sirfsoc_spi *sspi = spi_master_get_devdata(master); + int ret; + + ret = spi_master_suspend(master); + if (ret) + return ret; clk_disable(sspi->clk); return 0; @@ -764,7 +769,7 @@ static int spi_sirfsoc_resume(struct device *dev) writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_RXFIFO_OP); writel(SIRFSOC_SPI_FIFO_START, sspi->base + SIRFSOC_SPI_TXFIFO_OP); - return 0; + return spi_master_resume(master); } #endif From ed8eb250d7b097dbd888e46ad0d35a2cb1858221 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 13 Mar 2014 10:32:37 +0800 Subject: [PATCH 175/201] spi: sh-sci: Prevent NULL pointer dereference If sp->info is NULL, we will hit NULL pointer dereference in probe() while setting bus_num and num_chipselect for master: sp->bitbang.master->bus_num = sp->info->bus_num; sp->bitbang.master->num_chipselect = sp->info->num_chipselect; Thus add NULL test for sp->info in probe() to prevent NULL pointer dereference. Signed-off-by: Axel Lin Reviewed-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- drivers/spi/spi-sh-sci.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-sh-sci.c b/drivers/spi/spi-sh-sci.c index 38eb24df796c..41b1346b29d5 100644 --- a/drivers/spi/spi-sh-sci.c +++ b/drivers/spi/spi-sh-sci.c @@ -109,7 +109,7 @@ static void sh_sci_spi_chipselect(struct spi_device *dev, int value) { struct sh_sci_spi *sp = spi_master_get_devdata(dev->master); - if (sp->info && sp->info->chip_select) + if (sp->info->chip_select) (sp->info->chip_select)(sp->info, dev->chip_select, value); } @@ -131,6 +131,11 @@ static int sh_sci_spi_probe(struct platform_device *dev) platform_set_drvdata(dev, sp); sp->info = dev_get_platdata(&dev->dev); + if (!sp->info) { + dev_err(&dev->dev, "platform data is missing\n"); + ret = -ENOENT; + goto err1; + } /* setup spi bitbang adaptor */ sp->bitbang.master = master; From f2bb31057a42cb439161066db615ca73e4438e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 14 Mar 2014 21:34:22 +0100 Subject: [PATCH 176/201] spi: efm32: properly namespace location property MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While reviewing an i2c driver for efm32 that needs a similar property Wolfram Sang pointed out that "location" is a too generic name for something that is efm32 specific. So add an appropriate namespace and fall back to the generic name in case of failure. Signed-off-by: Uwe Kleine-König Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/efm32-spi.txt | 4 ++-- drivers/spi/spi-efm32.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt index a590ca51be75..25c02ba530da 100644 --- a/Documentation/devicetree/bindings/spi/efm32-spi.txt +++ b/Documentation/devicetree/bindings/spi/efm32-spi.txt @@ -8,7 +8,7 @@ Required properties: - interrupts: pair specifying rx and tx irq - clocks: phandle to the spi clock - cs-gpios: see spi-bus.txt -- location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values. +- efm32,location: Value to write to the ROUTE register's LOCATION bitfield to configure the pinmux for the device, see datasheet for values. Example: @@ -20,7 +20,7 @@ spi1: spi@0x4000c400 { /* USART1 */ interrupts = <15 16>; clocks = <&cmu 20>; cs-gpios = <&gpio 51 1>; // D3 - location = <1>; + efm32,location = <1>; status = "ok"; ks8851@0 { diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index 0512fedf1f13..fdb6fce0530b 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -294,7 +294,10 @@ static void efm32_spi_probe_dt(struct platform_device *pdev, u32 location; int ret; - ret = of_property_read_u32(np, "location", &location); + ret = of_property_read_u32(np, "efm32,location", &location); + if (ret) + /* fall back to old and (wrongly) generic property "location" */ + ret = of_property_read_u32(np, "location", &location); if (!ret) { dev_dbg(&pdev->dev, "using location %u\n", location); } else { From a6f87fad7b5132f026592729ccf65b995cdec35d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 17 Mar 2014 10:08:12 +0800 Subject: [PATCH 177/201] spi: core: Use master->max_speed_hz as transfer speed when xfer->speed_hz > master->max_speed_hz When xfer->speed_hz is greater than master->max_speed_hz, it's generally safe to use master->max_speed_hz as transfer speed. Thus use master->max_speed_hz as transfer speed rather than return error when xfer->speed_hz > master->max_speed_hz. Signed-off-by: Axel Lin Tested-by: Guenter Roeck Reviewed-by: Guenter Roeck Signed-off-by: Mark Brown --- drivers/spi/spi.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 9d1405440223..38e1c315bb13 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1653,12 +1653,13 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) message->frame_length += xfer->len; if (!xfer->bits_per_word) xfer->bits_per_word = spi->bits_per_word; - if (!xfer->speed_hz) { + + if (!xfer->speed_hz) xfer->speed_hz = spi->max_speed_hz; - if (master->max_speed_hz && - xfer->speed_hz > master->max_speed_hz) - xfer->speed_hz = master->max_speed_hz; - } + + if (master->max_speed_hz && + xfer->speed_hz > master->max_speed_hz) + xfer->speed_hz = master->max_speed_hz; if (master->bits_per_word_mask) { /* Only 32 bits fit in the mask */ @@ -1687,9 +1688,6 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) if (xfer->speed_hz && master->min_speed_hz && xfer->speed_hz < master->min_speed_hz) return -EINVAL; - if (xfer->speed_hz && master->max_speed_hz && - xfer->speed_hz > master->max_speed_hz) - return -EINVAL; if (xfer->tx_buf && !xfer->tx_nbits) xfer->tx_nbits = SPI_NBITS_SINGLE; From 7661ba5a84524587370c917ec1111c600ea57de8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Mar 2014 15:55:59 +0100 Subject: [PATCH 178/201] spi: remove obsolete spi-ti-ssp driver The tnetv107x platform is getting removed, so this driver will not be needed any more. Signed-off-by: Arnd Bergmann Acked-by: Sekhar Nori Acked-by: Kevin Hilman Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 7 - drivers/spi/Makefile | 1 - drivers/spi/spi-ti-ssp.c | 378 --------------------------------------- 3 files changed, 386 deletions(-) delete mode 100644 drivers/spi/spi-ti-ssp.c diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..fc940f109f6e 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -478,13 +478,6 @@ config SPI_TEGRA20_SLINK help SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. -config SPI_TI_SSP - tristate "TI Sequencer Serial Port - SPI Support" - depends on MFD_TI_SSP - help - This selects an SPI master implementation using a TI sequencer - serial port. - config SPI_TOPCLIFF_PCH tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" depends on PCI diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 95af48d2d360..7da53afaefdb 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -73,7 +73,6 @@ obj-$(CONFIG_SPI_SIRF) += spi-sirf.o obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o obj-$(CONFIG_SPI_TEGRA20_SFLASH) += spi-tegra20-sflash.o obj-$(CONFIG_SPI_TEGRA20_SLINK) += spi-tegra20-slink.o -obj-$(CONFIG_SPI_TI_SSP) += spi-ti-ssp.o obj-$(CONFIG_SPI_TLE62X0) += spi-tle62x0.o obj-$(CONFIG_SPI_TOPCLIFF_PCH) += spi-topcliff-pch.o obj-$(CONFIG_SPI_TXX9) += spi-txx9.o diff --git a/drivers/spi/spi-ti-ssp.c b/drivers/spi/spi-ti-ssp.c deleted file mode 100644 index 7d20e121e4c1..000000000000 --- a/drivers/spi/spi-ti-ssp.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Sequencer Serial Port (SSP) based SPI master driver - * - * Copyright (C) 2010 Texas Instruments Inc - * - * 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. - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define MODE_BITS (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH) - -struct ti_ssp_spi { - struct spi_master *master; - struct device *dev; - spinlock_t lock; - struct list_head msg_queue; - struct completion complete; - bool shutdown; - struct workqueue_struct *workqueue; - struct work_struct work; - u8 mode, bpw; - int cs_active; - u32 pc_en, pc_dis, pc_wr, pc_rd; - void (*select)(int cs); -}; - -static u32 ti_ssp_spi_rx(struct ti_ssp_spi *hw) -{ - u32 ret; - - ti_ssp_run(hw->dev, hw->pc_rd, 0, &ret); - return ret; -} - -static void ti_ssp_spi_tx(struct ti_ssp_spi *hw, u32 data) -{ - ti_ssp_run(hw->dev, hw->pc_wr, data << (32 - hw->bpw), NULL); -} - -static int ti_ssp_spi_txrx(struct ti_ssp_spi *hw, struct spi_message *msg, - struct spi_transfer *t) -{ - int count; - - if (hw->bpw <= 8) { - u8 *rx = t->rx_buf; - const u8 *tx = t->tx_buf; - - for (count = 0; count < t->len; count += 1) { - if (t->tx_buf) - ti_ssp_spi_tx(hw, *tx++); - if (t->rx_buf) - *rx++ = ti_ssp_spi_rx(hw); - } - } else if (hw->bpw <= 16) { - u16 *rx = t->rx_buf; - const u16 *tx = t->tx_buf; - - for (count = 0; count < t->len; count += 2) { - if (t->tx_buf) - ti_ssp_spi_tx(hw, *tx++); - if (t->rx_buf) - *rx++ = ti_ssp_spi_rx(hw); - } - } else { - u32 *rx = t->rx_buf; - const u32 *tx = t->tx_buf; - - for (count = 0; count < t->len; count += 4) { - if (t->tx_buf) - ti_ssp_spi_tx(hw, *tx++); - if (t->rx_buf) - *rx++ = ti_ssp_spi_rx(hw); - } - } - - msg->actual_length += count; /* bytes transferred */ - - dev_dbg(&msg->spi->dev, "xfer %s%s, %d bytes, %d bpw, count %d%s\n", - t->tx_buf ? "tx" : "", t->rx_buf ? "rx" : "", t->len, - hw->bpw, count, (count < t->len) ? " (under)" : ""); - - return (count < t->len) ? -EIO : 0; /* left over data */ -} - -static void ti_ssp_spi_chip_select(struct ti_ssp_spi *hw, int cs_active) -{ - cs_active = !!cs_active; - if (cs_active == hw->cs_active) - return; - ti_ssp_run(hw->dev, cs_active ? hw->pc_en : hw->pc_dis, 0, NULL); - hw->cs_active = cs_active; -} - -#define __SHIFT_OUT(bits) (SSP_OPCODE_SHIFT | SSP_OUT_MODE | \ - cs_en | clk | SSP_COUNT((bits) * 2 - 1)) -#define __SHIFT_IN(bits) (SSP_OPCODE_SHIFT | SSP_IN_MODE | \ - cs_en | clk | SSP_COUNT((bits) * 2 - 1)) - -static int ti_ssp_spi_setup_transfer(struct ti_ssp_spi *hw, u8 bpw, u8 mode) -{ - int error, idx = 0; - u32 seqram[16]; - u32 cs_en, cs_dis, clk; - u32 topbits, botbits; - - mode &= MODE_BITS; - if (mode == hw->mode && bpw == hw->bpw) - return 0; - - cs_en = (mode & SPI_CS_HIGH) ? SSP_CS_HIGH : SSP_CS_LOW; - cs_dis = (mode & SPI_CS_HIGH) ? SSP_CS_LOW : SSP_CS_HIGH; - clk = (mode & SPI_CPOL) ? SSP_CLK_HIGH : SSP_CLK_LOW; - - /* Construct instructions */ - - /* Disable Chip Select */ - hw->pc_dis = idx; - seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_dis | clk; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_dis | clk; - - /* Enable Chip Select */ - hw->pc_en = idx; - seqram[idx++] = SSP_OPCODE_DIRECT | SSP_OUT_MODE | cs_en | clk; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; - - /* Reads and writes need to be split for bpw > 16 */ - topbits = (bpw > 16) ? 16 : bpw; - botbits = bpw - topbits; - - /* Write */ - hw->pc_wr = idx; - seqram[idx++] = __SHIFT_OUT(topbits) | SSP_ADDR_REG; - if (botbits) - seqram[idx++] = __SHIFT_OUT(botbits) | SSP_DATA_REG; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; - - /* Read */ - hw->pc_rd = idx; - if (botbits) - seqram[idx++] = __SHIFT_IN(botbits) | SSP_ADDR_REG; - seqram[idx++] = __SHIFT_IN(topbits) | SSP_DATA_REG; - seqram[idx++] = SSP_OPCODE_STOP | SSP_OUT_MODE | cs_en | clk; - - error = ti_ssp_load(hw->dev, 0, seqram, idx); - if (error < 0) - return error; - - error = ti_ssp_set_mode(hw->dev, ((mode & SPI_CPHA) ? - 0 : SSP_EARLY_DIN)); - if (error < 0) - return error; - - hw->bpw = bpw; - hw->mode = mode; - - return error; -} - -static void ti_ssp_spi_work(struct work_struct *work) -{ - struct ti_ssp_spi *hw = container_of(work, struct ti_ssp_spi, work); - - spin_lock(&hw->lock); - - while (!list_empty(&hw->msg_queue)) { - struct spi_message *m; - struct spi_device *spi; - struct spi_transfer *t = NULL; - int status = 0; - - m = container_of(hw->msg_queue.next, struct spi_message, - queue); - - list_del_init(&m->queue); - - spin_unlock(&hw->lock); - - spi = m->spi; - - if (hw->select) - hw->select(spi->chip_select); - - list_for_each_entry(t, &m->transfers, transfer_list) { - int bpw = spi->bits_per_word; - int xfer_status; - - if (t->bits_per_word) - bpw = t->bits_per_word; - - if (ti_ssp_spi_setup_transfer(hw, bpw, spi->mode) < 0) - break; - - ti_ssp_spi_chip_select(hw, 1); - - xfer_status = ti_ssp_spi_txrx(hw, m, t); - if (xfer_status < 0) - status = xfer_status; - - if (t->delay_usecs) - udelay(t->delay_usecs); - - if (t->cs_change) - ti_ssp_spi_chip_select(hw, 0); - } - - ti_ssp_spi_chip_select(hw, 0); - m->status = status; - m->complete(m->context); - - spin_lock(&hw->lock); - } - - if (hw->shutdown) - complete(&hw->complete); - - spin_unlock(&hw->lock); -} - -static int ti_ssp_spi_transfer(struct spi_device *spi, struct spi_message *m) -{ - struct ti_ssp_spi *hw; - struct spi_transfer *t; - int error = 0; - - m->actual_length = 0; - m->status = -EINPROGRESS; - - hw = spi_master_get_devdata(spi->master); - - if (list_empty(&m->transfers) || !m->complete) - return -EINVAL; - - list_for_each_entry(t, &m->transfers, transfer_list) { - if (t->len && !(t->rx_buf || t->tx_buf)) { - dev_err(&spi->dev, "invalid xfer, no buffer\n"); - return -EINVAL; - } - - if (t->len && t->rx_buf && t->tx_buf) { - dev_err(&spi->dev, "invalid xfer, full duplex\n"); - return -EINVAL; - } - } - - spin_lock(&hw->lock); - if (hw->shutdown) { - error = -ESHUTDOWN; - goto error_unlock; - } - list_add_tail(&m->queue, &hw->msg_queue); - queue_work(hw->workqueue, &hw->work); -error_unlock: - spin_unlock(&hw->lock); - return error; -} - -static int ti_ssp_spi_probe(struct platform_device *pdev) -{ - const struct ti_ssp_spi_data *pdata; - struct ti_ssp_spi *hw; - struct spi_master *master; - struct device *dev = &pdev->dev; - int error = 0; - - pdata = dev_get_platdata(dev); - if (!pdata) { - dev_err(dev, "platform data not found\n"); - return -EINVAL; - } - - master = spi_alloc_master(dev, sizeof(struct ti_ssp_spi)); - if (!master) { - dev_err(dev, "cannot allocate SPI master\n"); - return -ENOMEM; - } - - hw = spi_master_get_devdata(master); - platform_set_drvdata(pdev, hw); - - hw->master = master; - hw->dev = dev; - hw->select = pdata->select; - - spin_lock_init(&hw->lock); - init_completion(&hw->complete); - INIT_LIST_HEAD(&hw->msg_queue); - INIT_WORK(&hw->work, ti_ssp_spi_work); - - hw->workqueue = create_singlethread_workqueue(dev_name(dev)); - if (!hw->workqueue) { - error = -ENOMEM; - dev_err(dev, "work queue creation failed\n"); - goto error_wq; - } - - error = ti_ssp_set_iosel(hw->dev, pdata->iosel); - if (error < 0) { - dev_err(dev, "io setup failed\n"); - goto error_iosel; - } - - master->bus_num = pdev->id; - master->num_chipselect = pdata->num_cs; - master->mode_bits = MODE_BITS; - master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32); - master->flags = SPI_MASTER_HALF_DUPLEX; - master->transfer = ti_ssp_spi_transfer; - - error = spi_register_master(master); - if (error) { - dev_err(dev, "master registration failed\n"); - goto error_reg; - } - - return 0; - -error_reg: -error_iosel: - destroy_workqueue(hw->workqueue); -error_wq: - spi_master_put(master); - return error; -} - -static int ti_ssp_spi_remove(struct platform_device *pdev) -{ - struct ti_ssp_spi *hw = platform_get_drvdata(pdev); - int error; - - hw->shutdown = 1; - while (!list_empty(&hw->msg_queue)) { - error = wait_for_completion_interruptible(&hw->complete); - if (error < 0) { - hw->shutdown = 0; - return error; - } - } - destroy_workqueue(hw->workqueue); - spi_unregister_master(hw->master); - - return 0; -} - -static struct platform_driver ti_ssp_spi_driver = { - .probe = ti_ssp_spi_probe, - .remove = ti_ssp_spi_remove, - .driver = { - .name = "ti-ssp-spi", - .owner = THIS_MODULE, - }, -}; -module_platform_driver(ti_ssp_spi_driver); - -MODULE_DESCRIPTION("SSP SPI Master"); -MODULE_AUTHOR("Cyril Chemparathy"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:ti-ssp-spi"); From 54f4c51cc1634ab91074389dd6809af938a72778 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Fri, 21 Mar 2014 08:53:41 -0700 Subject: [PATCH 179/201] spi: atmel: fix printk format warnings Fix printk format warning by using %p extension 'ad' for dma_addr_t. drivers/spi/spi-atmel.c:1228:3: warning: format '%x' expects argument of type 'unsigned int', but argument 7 has type 'dma_addr_t' [-Wformat] drivers/spi/spi-atmel.c:1228:3: warning: format '%x' expects argument of type 'unsigned int', but argument 9 has type 'dma_addr_t' [-Wformat] Signed-off-by: Randy Dunlap Acked-by: Nicolas Ferre Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index c83b0c620fa1..f17f949857b4 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1234,10 +1234,10 @@ static int atmel_spi_transfer_one_message(struct spi_master *master, list_for_each_entry(xfer, &msg->transfers, transfer_list) { dev_dbg(&spi->dev, - " xfer %p: len %u tx %p/%08x rx %p/%08x\n", + " xfer %p: len %u tx %p/%pad rx %p/%pad\n", xfer, xfer->len, - xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + xfer->tx_buf, &xfer->tx_dma, + xfer->rx_buf, &xfer->rx_dma); } msg_done: From fb534f10755954827a4b71b9a21f9b5fa93707a9 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Mar 2014 13:24:14 +0800 Subject: [PATCH 180/201] spi: nuc900: Fix setting multiple bits settings in register The correct way to set multiple bits settings is always clear these bit fields before set new settings. Current code does not cause problem because the reset value of these bit fields are 0, and these settings only set once during probe. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-nuc900.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 6d36c35c86f5..f12e27cdbf49 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -38,7 +38,9 @@ /* usi register bit */ #define ENINT (0x01 << 17) #define ENFLG (0x01 << 16) +#define SLEEP (0x0f << 12) #define TXNUM (0x03 << 8) +#define TXBITLEN (0x1f << 3) #define TXNEG (0x01 << 2) #define RXNEG (0x01 << 1) #define LSB (0x01 << 10) @@ -116,19 +118,16 @@ static void nuc900_spi_chipsel(struct spi_device *spi, int value) } } -static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, - unsigned int txnum) +static void nuc900_spi_setup_txnum(struct nuc900_spi *hw, unsigned int txnum) { unsigned int val; unsigned long flags; spin_lock_irqsave(&hw->lock, flags); - val = __raw_readl(hw->regs + USI_CNT); + val = __raw_readl(hw->regs + USI_CNT) & ~TXNUM; - if (!txnum) - val &= ~TXNUM; - else + if (txnum) val |= txnum << 0x08; __raw_writel(val, hw->regs + USI_CNT); @@ -145,7 +144,7 @@ static void nuc900_spi_setup_txbitlen(struct nuc900_spi *hw, spin_lock_irqsave(&hw->lock, flags); - val = __raw_readl(hw->regs + USI_CNT); + val = __raw_readl(hw->regs + USI_CNT) & ~TXBITLEN; val |= (txbitlen << 0x03); @@ -284,12 +283,11 @@ static void nuc900_set_sleep(struct nuc900_spi *hw, unsigned int sleep) spin_lock_irqsave(&hw->lock, flags); - val = __raw_readl(hw->regs + USI_CNT); + val = __raw_readl(hw->regs + USI_CNT) & ~SLEEP; if (sleep) val |= (sleep << 12); - else - val &= ~(0x0f << 12); + __raw_writel(val, hw->regs + USI_CNT); spin_unlock_irqrestore(&hw->lock, flags); From be8dde46750be49fbf161dccd568b5cd14d3f004 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 20 Mar 2014 18:08:04 +0800 Subject: [PATCH 181/201] spi: xtensa-xtfpga: Enable driver compilation with COMPILE_TEST This helps increasing build testing coverage. Signed-off-by: Axel Lin Reviewed-by: Max Filippov Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index c87475db0f79..d36045f4fc24 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -522,7 +522,7 @@ config SPI_XILINX config SPI_XTENSA_XTFPGA tristate "Xtensa SPI controller for xtfpga" - depends on XTENSA && XTENSA_PLATFORM_XTFPGA + depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST select SPI_BITBANG help SPI driver for xtfpga SPI master controller. From 7282326b722995c3fabd4dcd9244182b37500252 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 20 Mar 2014 17:20:17 +0800 Subject: [PATCH 182/201] spi: fsl-lib: Fix memory leak of pinfo of_mpc8xxx_spi_probe() allocates memory for pinfo but the memory is not freed anywhere. of_mpc8xxx_spi_probe() is called in .probe() and pinfo should be freed in .remove(), so convert kzalloc to devm_kzalloc to fix the memory leak. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-lib.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c index 0b75f26158ab..e5d45fca3551 100644 --- a/drivers/spi/spi-fsl-lib.c +++ b/drivers/spi/spi-fsl-lib.c @@ -200,7 +200,7 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) const void *prop; int ret = -ENOMEM; - pinfo = kzalloc(sizeof(*pinfo), GFP_KERNEL); + pinfo = devm_kzalloc(&ofdev->dev, sizeof(*pinfo), GFP_KERNEL); if (!pinfo) return -ENOMEM; @@ -215,15 +215,13 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) pdata->sysclk = get_brgfreq(); if (pdata->sysclk == -1) { pdata->sysclk = fsl_get_sys_freq(); - if (pdata->sysclk == -1) { - ret = -ENODEV; - goto err; - } + if (pdata->sysclk == -1) + return -ENODEV; } #else ret = of_property_read_u32(np, "clock-frequency", &pdata->sysclk); if (ret) - goto err; + return ret; #endif prop = of_get_property(np, "mode", NULL); @@ -237,8 +235,4 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev) pdata->flags = SPI_CPM_MODE | SPI_CPM1; return 0; - -err: - kfree(pinfo); - return ret; } From bf2f2f7958388b2000736452fd7a126182ee69d0 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Mar 2014 11:21:58 +0800 Subject: [PATCH 183/201] spi: altera: Remove the code to get unused platform_data The definition of struct altera_spi_platform_data does not exist in current tree. So remove the code to get platform_data which is never used. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-altera.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-altera.c b/drivers/spi/spi-altera.c index aa33b56b7a92..09df64950234 100644 --- a/drivers/spi/spi-altera.c +++ b/drivers/spi/spi-altera.c @@ -200,7 +200,6 @@ static irqreturn_t altera_spi_irq(int irq, void *dev) static int altera_spi_probe(struct platform_device *pdev) { - struct altera_spi_platform_data *platp = dev_get_platdata(&pdev->dev); struct altera_spi *hw; struct spi_master *master; struct resource *res; @@ -215,6 +214,7 @@ static int altera_spi_probe(struct platform_device *pdev) master->num_chipselect = 16; master->mode_bits = SPI_CS_HIGH; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 16); + master->dev.of_node = pdev->dev.of_node; hw = spi_master_get_devdata(master); platform_set_drvdata(pdev, hw); @@ -246,9 +246,6 @@ static int altera_spi_probe(struct platform_device *pdev) if (err) goto exit; } - /* find platform data */ - if (!platp) - hw->bitbang.master->dev.of_node = pdev->dev.of_node; /* register our spi controller */ err = spi_bitbang_start(&hw->bitbang); From f0a71337be7f19cc929aabfffc3ecd4c056df03a Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Mar 2014 22:59:58 +0800 Subject: [PATCH 184/201] spi: fsl-espi: Remove unused bits_per_word variable in fsl_espi_bufs Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-espi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c index 428dc7a6b62e..6fb2b75df821 100644 --- a/drivers/spi/spi-fsl-espi.c +++ b/drivers/spi/spi-fsl-espi.c @@ -219,13 +219,8 @@ static int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); struct fsl_espi_reg *reg_base = mpc8xxx_spi->reg_base; unsigned int len = t->len; - u8 bits_per_word; int ret; - bits_per_word = spi->bits_per_word; - if (t->bits_per_word) - bits_per_word = t->bits_per_word; - mpc8xxx_spi->len = t->len; len = roundup(len, 4) / 4; From b86e81d9a7d28a658904d8b14da7b5cb0d8f8a21 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Mar 2014 15:46:55 +0800 Subject: [PATCH 185/201] spi: topcliff-pch: Properly unregister platform devices on probe() error paths Ensure all registered platform devices are unregistered on probe() error paths. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index dc5d2d489953..372811aa5fb2 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -1568,8 +1568,7 @@ static struct platform_driver pch_spi_pd_driver = { .resume = pch_spi_pd_resume }; -static int pch_spi_probe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct pch_spi_board_data *board_dat; struct platform_device *pd_dev = NULL; @@ -1639,6 +1638,8 @@ static int pch_spi_probe(struct pci_dev *pdev, return 0; err_platform_device: + while (--i >= 0) + platform_device_unregister(pd_dev_save->pd_save[i]); pci_disable_device(pdev); pci_enable_device: pci_release_regions(pdev); From 3dc925945b00c231419e12c00c998cdcc3a6b8cf Mon Sep 17 00:00:00 2001 From: Alexander Shiyan Date: Sat, 22 Mar 2014 10:57:35 +0400 Subject: [PATCH 186/201] spi: clps711x: Remove dependency This patch removes dependency. This is performed by replace hard coded used memory regions and interrupt to getting these values from resources passed to the driver. For the system-wide registers we now able to use SYSCON driver. Signed-off-by: Alexander Shiyan Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 94 +++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 33 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index ab010c05dc5a..d9eec4e3b246 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -17,14 +17,21 @@ #include #include #include +#include +#include +#include #include #include -#include - #define DRIVER_NAME "spi-clps711x" +#define SYNCIO_FRMLEN(x) ((x) << 8) +#define SYNCIO_TXFRMEN (1 << 14) + struct spi_clps711x_data { + void __iomem *syncio; + struct regmap *syscon; + struct regmap *syscon1; struct clk *spi_clk; u32 max_speed_hz; @@ -49,31 +56,29 @@ static void spi_clps711x_setup_xfer(struct spi_device *spi, /* Setup SPI frequency divider */ if (!xfer->speed_hz || (xfer->speed_hz >= hw->max_speed_hz)) - clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | - SYSCON1_ADCKSEL(3), SYSCON1); + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3)); else if (xfer->speed_hz >= (hw->max_speed_hz / 2)) - clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | - SYSCON1_ADCKSEL(2), SYSCON1); + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2)); else if (xfer->speed_hz >= (hw->max_speed_hz / 8)) - clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | - SYSCON1_ADCKSEL(1), SYSCON1); + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1)); else - clps_writel((clps_readl(SYSCON1) & ~SYSCON1_ADCKSEL_MASK) | - SYSCON1_ADCKSEL(0), SYSCON1); + regmap_update_bits(hw->syscon1, SYSCON_OFFSET, + SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(0)); } static int spi_clps711x_prepare_message(struct spi_master *master, struct spi_message *msg) { + struct spi_clps711x_data *hw = spi_master_get_devdata(master); struct spi_device *spi = msg->spi; - /* Setup edge for transfer */ - if (spi->mode & SPI_CPHA) - clps_writew(clps_readw(SYSCON3) | SYSCON3_ADCCKNSEN, SYSCON3); - else - clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCKNSEN, SYSCON3); - - return 0; + /* Setup mode for transfer */ + return regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCKNSEN, + (spi->mode & SPI_CPHA) ? + SYSCON3_ADCCKNSEN : 0); } static int spi_clps711x_transfer_one(struct spi_master *master, @@ -92,7 +97,8 @@ static int spi_clps711x_transfer_one(struct spi_master *master, /* Initiate transfer */ data = hw->tx_buf ? *hw->tx_buf++ : 0; - clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, SYNCIO); + writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, hw->syncio); + return 1; } @@ -103,15 +109,15 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) u8 data; /* Handle RX */ - data = clps_readb(SYNCIO); + data = readb(hw->syncio); if (hw->rx_buf) *hw->rx_buf++ = data; /* Handle TX */ if (--hw->len > 0) { data = hw->tx_buf ? *hw->tx_buf++ : 0; - clps_writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, - SYNCIO); + writel(data | SYNCIO_FRMLEN(hw->bpw) | SYNCIO_TXFRMEN, + hw->syncio); } else spi_finalize_current_transfer(master); @@ -120,10 +126,11 @@ static irqreturn_t spi_clps711x_isr(int irq, void *dev_id) static int spi_clps711x_probe(struct platform_device *pdev) { - int i, ret; - struct spi_master *master; struct spi_clps711x_data *hw; struct spi_clps711x_pdata *pdata = dev_get_platdata(&pdev->dev); + struct spi_master *master; + struct resource *res; + int i, irq, ret; if (!pdata) { dev_err(&pdev->dev, "No platform data supplied\n"); @@ -135,6 +142,10 @@ static int spi_clps711x_probe(struct platform_device *pdev) return -EINVAL; } + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + master = spi_alloc_master(&pdev->dev, sizeof(*hw)); if (!master) return -ENOMEM; @@ -176,19 +187,36 @@ static int spi_clps711x_probe(struct platform_device *pdev) platform_set_drvdata(pdev, master); - /* Disable extended mode due hardware problems */ - clps_writew(clps_readw(SYSCON3) & ~SYSCON3_ADCCON, SYSCON3); - - /* Clear possible pending interrupt */ - clps_readl(SYNCIO); - - ret = devm_request_irq(&pdev->dev, IRQ_SSEOTI, spi_clps711x_isr, 0, - dev_name(&pdev->dev), master); - if (ret) { - dev_err(&pdev->dev, "Can't request IRQ\n"); + hw->syscon = syscon_regmap_lookup_by_pdevname("syscon.3"); + if (IS_ERR(hw->syscon)) { + ret = PTR_ERR(hw->syscon); goto err_out; } + hw->syscon1 = syscon_regmap_lookup_by_pdevname("syscon.1"); + if (IS_ERR(hw->syscon1)) { + ret = PTR_ERR(hw->syscon1); + goto err_out; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hw->syncio = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hw->syncio)) { + ret = PTR_ERR(hw->syncio); + goto err_out; + } + + /* Disable extended mode due hardware problems */ + regmap_update_bits(hw->syscon, SYSCON_OFFSET, SYSCON3_ADCCON, 0); + + /* Clear possible pending interrupt */ + readl(hw->syncio); + + ret = devm_request_irq(&pdev->dev, irq, spi_clps711x_isr, 0, + dev_name(&pdev->dev), master); + if (ret) + goto err_out; + ret = devm_spi_register_master(&pdev->dev, master); if (!ret) { dev_info(&pdev->dev, From 12f6dd860cf8bf036c0bec38c00a53da71bcd43a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 25 Mar 2014 15:51:50 +0100 Subject: [PATCH 187/201] spi: efm32: use $vendor,$device scheme for compatible string MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wolfram Sang pointed out that "efm32,$device" is non-standard. So use the common scheme and prefix device with "efm32-". The old compatible string is left in place until arch/arm/boot/dts/efm32* is fixed. Signed-off-by: Uwe Kleine-König Acked-by: Wolfram Sang Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- Documentation/devicetree/bindings/spi/efm32-spi.txt | 4 ++-- drivers/spi/spi-efm32.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/efm32-spi.txt b/Documentation/devicetree/bindings/spi/efm32-spi.txt index 25c02ba530da..8f081c96a4fa 100644 --- a/Documentation/devicetree/bindings/spi/efm32-spi.txt +++ b/Documentation/devicetree/bindings/spi/efm32-spi.txt @@ -3,7 +3,7 @@ Required properties: - #address-cells: see spi-bus.txt - #size-cells: see spi-bus.txt -- compatible: should be "efm32,spi" +- compatible: should be "energymicro,efm32-spi" - reg: Offset and length of the register set for the controller - interrupts: pair specifying rx and tx irq - clocks: phandle to the spi clock @@ -15,7 +15,7 @@ Example: spi1: spi@0x4000c400 { /* USART1 */ #address-cells = <1>; #size-cells = <0>; - compatible = "efm32,spi"; + compatible = "energymicro,efm32-spi"; reg = <0x4000c400 0x400>; interrupts = <15 16>; clocks = <&cmu 20>; diff --git a/drivers/spi/spi-efm32.c b/drivers/spi/spi-efm32.c index fdb6fce0530b..4a5a359dafca 100644 --- a/drivers/spi/spi-efm32.c +++ b/drivers/spi/spi-efm32.c @@ -471,6 +471,9 @@ static int efm32_spi_remove(struct platform_device *pdev) static const struct of_device_id efm32_spi_dt_ids[] = { { + .compatible = "energymicro,efm32-spi", + }, { + /* doesn't follow the "vendor,device" scheme, don't use */ .compatible = "efm32,spi", }, { /* sentinel */ From 7f8cf088f027885d78dca6cc2ca7566d8e894c6e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Mar 2014 10:04:06 +0800 Subject: [PATCH 188/201] spi: bcm63xx: Remove unused define for PFX Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-bcm63xx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c index 77286aef2adf..b3d719a9667a 100644 --- a/drivers/spi/spi-bcm63xx.c +++ b/drivers/spi/spi-bcm63xx.c @@ -35,8 +35,6 @@ #include -#define PFX KBUILD_MODNAME - #define BCM63XX_SPI_MAX_PREPEND 15 struct bcm63xx_spi { From 8023d384ff5c55a431c1a9a84cd76648d43ba7d8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 20 Mar 2014 22:59:06 +0800 Subject: [PATCH 189/201] spi: coldfire-qspi: Simplify the code to set register bits for transfer speed spi core will use spi->max_speed_hz as transfer speed if the transfer speed was not set. So we don't need to test t->speed_hz in mcfqspi_transfer_one(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-coldfire-qspi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 6d78f96bdc55..492ceb1654e5 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -321,10 +321,7 @@ static int mcfqspi_transfer_one(struct spi_master *master, qmr |= MCFQSPI_QMR_CPHA; if (spi->mode & SPI_CPOL) qmr |= MCFQSPI_QMR_CPOL; - if (t->speed_hz) - qmr |= mcfqspi_qmr_baud(t->speed_hz); - else - qmr |= mcfqspi_qmr_baud(spi->max_speed_hz); + qmr |= mcfqspi_qmr_baud(t->speed_hz); mcfqspi_wr_qmr(mcfqspi, qmr); mcfqspi_wr_qir(mcfqspi, MCFQSPI_QIR_SPIFE); From 342451df07109f865e6c108b7205e9738e814f3f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 25 Mar 2014 08:10:32 +0100 Subject: [PATCH 190/201] spi: topcliff-pch: Transform noisy message to dev_vdbg If during a SPI transfer with len larger than PCH_MAX_FIFO_DEPTH and the IRQ handler happens to be called when the transmit FIFO is already empty, and SPSR_FI_BIT is set consequently, the message "spi_master spi32766: pch_spi_handler_sub : Transfer is not completed" is spammed to the systemlog, because tx_index has already increased further due to the next bytes to be written. This case is uncritical as new bytes have already been written. Signed-off-by: Alexander Stein Signed-off-by: Mark Brown --- drivers/spi/spi-topcliff-pch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 372811aa5fb2..8fa1a6cbc42b 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -332,7 +332,7 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, data->transfer_active = false; wake_up(&data->wait); } else { - dev_err(&data->master->dev, + dev_vdbg(&data->master->dev, "%s : Transfer is not completed", __func__); } From 1e25cd4729bd76662d02b142a6a7f8504bb6aea7 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 25 Mar 2014 19:28:22 +0000 Subject: [PATCH 191/201] spi: Do not require a completion There is no real reason why we require transfers to have a completion and the only user of the completion now checks to see if one has been provided before using it so stop enforcing this. This makes it more convenient for drivers to chain multiple asynchronous transfers together. Signed-off-by: Mark Brown --- drivers/spi/spi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 38e1c315bb13..d94782340b47 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -1621,8 +1621,6 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message) if (list_empty(&message->transfers)) return -EINVAL; - if (!message->complete) - return -EINVAL; /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where From d7a7f6ec14fb07ed9c1167db760bc535b742b382 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 26 Mar 2014 19:22:08 +0800 Subject: [PATCH 192/201] spi: omap-uwire: Remove full duplex check This driver sets the SPI_MASTER_HALF_DUPLEX flag, so the spi core will check transfers to ensure they are not full duplex. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-omap-uwire.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 95cc6948a2ba..f5176bbfa6f1 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -218,10 +218,6 @@ static int uwire_txrx(struct spi_device *spi, struct spi_transfer *t) if (!t->tx_buf && !t->rx_buf) return 0; - /* Microwire doesn't read and write concurrently */ - if (t->tx_buf && t->rx_buf) - return -EPERM; - w = spi->chip_select << 10; w |= CS_CMD; From 5634dd8bf422e0e5b71bb9762ff079f01a5f9a83 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 26 Mar 2014 16:53:18 +0800 Subject: [PATCH 193/201] spi: clps711x: Enable driver compilation with COMPILE_TEST This helps increasing build testing coverage. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..9b77b0f59b96 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -150,7 +150,7 @@ config SPI_BUTTERFLY config SPI_CLPS711X tristate "CLPS711X host SPI controller" - depends on ARCH_CLPS711X + depends on ARCH_CLPS711X || COMPILE_TEST help This enables dedicated general purpose SPI/Microwire1-compatible master mode interface (SSI1) for CLPS711X-based CPUs. From 6f50c6bc61d4f8cac9dfa21d2db3917deb9beb20 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 26 Mar 2014 23:44:18 +0800 Subject: [PATCH 194/201] spi: clps711x: Convert to use master->max_speed_hz Set highest transfer speed to master->max_speed_hz and then we can remove hw->max_speed. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-clps711x.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-clps711x.c b/drivers/spi/spi-clps711x.c index d9eec4e3b246..a2b8ef5d8c59 100644 --- a/drivers/spi/spi-clps711x.c +++ b/drivers/spi/spi-clps711x.c @@ -33,7 +33,6 @@ struct spi_clps711x_data { struct regmap *syscon; struct regmap *syscon1; struct clk *spi_clk; - u32 max_speed_hz; u8 *tx_buf; u8 *rx_buf; @@ -52,16 +51,17 @@ static int spi_clps711x_setup(struct spi_device *spi) static void spi_clps711x_setup_xfer(struct spi_device *spi, struct spi_transfer *xfer) { - struct spi_clps711x_data *hw = spi_master_get_devdata(spi->master); + struct spi_master *master = spi->master; + struct spi_clps711x_data *hw = spi_master_get_devdata(master); /* Setup SPI frequency divider */ - if (!xfer->speed_hz || (xfer->speed_hz >= hw->max_speed_hz)) + if (xfer->speed_hz >= master->max_speed_hz) regmap_update_bits(hw->syscon1, SYSCON_OFFSET, SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(3)); - else if (xfer->speed_hz >= (hw->max_speed_hz / 2)) + else if (xfer->speed_hz >= (master->max_speed_hz / 2)) regmap_update_bits(hw->syscon1, SYSCON_OFFSET, SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(2)); - else if (xfer->speed_hz >= (hw->max_speed_hz / 8)) + else if (xfer->speed_hz >= (master->max_speed_hz / 8)) regmap_update_bits(hw->syscon1, SYSCON_OFFSET, SYSCON1_ADCKSEL_MASK, SYSCON1_ADCKSEL(1)); else @@ -183,7 +183,7 @@ static int spi_clps711x_probe(struct platform_device *pdev) ret = PTR_ERR(hw->spi_clk); goto err_out; } - hw->max_speed_hz = clk_get_rate(hw->spi_clk); + master->max_speed_hz = clk_get_rate(hw->spi_clk); platform_set_drvdata(pdev, master); @@ -221,7 +221,7 @@ static int spi_clps711x_probe(struct platform_device *pdev) if (!ret) { dev_info(&pdev->dev, "SPI bus driver initialized. Master clock %u Hz\n", - hw->max_speed_hz); + master->max_speed_hz); return 0; } From cbab80464f7470432b4b8061333c572a8b9a713f Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Thu, 27 Mar 2014 11:07:59 -0500 Subject: [PATCH 195/201] spi: omap-uwire: add missing iounmap This fixes the following coccicheck warning: linux-2.6/drivers/spi/spi-omap-uwire.c:485:2-8: ERROR: missing iounmap; ioremap on line 471 and execution via conditional on line 481 Signed-off-by: Nishanth Menon Signed-off-by: Mark Brown --- drivers/spi/spi-omap-uwire.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index f5176bbfa6f1..31ce92ff738b 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -478,6 +478,7 @@ static int uwire_probe(struct platform_device *pdev) status = PTR_ERR(uwire->ck); dev_dbg(&pdev->dev, "no functional clock?\n"); spi_master_put(master); + iounmap(uwire_base); return status; } clk_enable(uwire->ck); From 0e0cd9ea8961b82947a40471080e7968b634820e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Mar 2014 09:19:05 +0800 Subject: [PATCH 196/201] spi: fsl-dspi: Fix memory leak The memory allocated for chip is not freed anywhere. Convert to use devm_kzalloc to fix the memory leak. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-fsl-dspi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 7f0dddb21833..c5ecfc1240ab 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -342,7 +342,8 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) /* Only alloc on first setup */ chip = spi_get_ctldata(spi); if (chip == NULL) { - chip = kcalloc(1, sizeof(struct chip_data), GFP_KERNEL); + chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data), + GFP_KERNEL); if (!chip) return -ENOMEM; } @@ -353,7 +354,6 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) fmsz = spi->bits_per_word - 1; } else { pr_err("Invalid wordsize\n"); - kfree(chip); return -ENODEV; } From c63f5da00845143de621e991ea186be0829647ee Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Mar 2014 12:44:13 +0800 Subject: [PATCH 197/201] spi: dw: Don't call kfree for memory allocated by devm_kzalloc With devm_kzalloc, the memory is automatically freed when spi_device detach from the bus. Fixes: commit 43f627ac9de42 (spi: dw: fix memory leak on error path) Signed-off-by: Axel Lin Acked-by: Baruch Siach Signed-off-by: Mark Brown Cc: stabe@vger.kernel.org --- drivers/spi/spi-dw.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 9e4a0aa7d341..79fd1fa95bf2 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c @@ -665,12 +665,6 @@ static int dw_spi_setup(struct spi_device *spi) return 0; } -static void dw_spi_cleanup(struct spi_device *spi) -{ - struct chip_data *chip = spi_get_ctldata(spi); - kfree(chip); -} - static int init_queue(struct dw_spi *dws) { INIT_LIST_HEAD(&dws->queue); @@ -800,7 +794,6 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws) master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); master->bus_num = dws->bus_num; master->num_chipselect = dws->num_cs; - master->cleanup = dw_spi_cleanup; master->setup = dw_spi_setup; master->transfer = dw_spi_transfer; master->max_speed_hz = dws->max_freq; From d1c18caace25aa8b6fcfe4dc78e96a031f1eab2d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Mar 2014 15:03:37 +0800 Subject: [PATCH 198/201] spi: omap-100k: Fix memory leak The memory allocated for cs is not freed anywhere. Convert to use devm_kzalloc to fix the memory leak. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-omap-100k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c index c9e228242643..e7ffcded4e14 100644 --- a/drivers/spi/spi-omap-100k.c +++ b/drivers/spi/spi-omap-100k.c @@ -283,7 +283,7 @@ static int omap1_spi100k_setup(struct spi_device *spi) spi100k = spi_master_get_devdata(spi->master); if (!cs) { - cs = kzalloc(sizeof(*cs), GFP_KERNEL); + cs = devm_kzalloc(&spi->dev, sizeof(*cs), GFP_KERNEL); if (!cs) return -ENOMEM; cs->base = spi100k->base + spi->chip_select * 0x14; From 5c5989ccd32c37890115a6dd5c03f39cba7f7beb Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Mar 2014 23:37:54 +0800 Subject: [PATCH 199/201] spi: mpc52xx: Convert to use bits_per_word_mask This controller only supports 8-bit word length. Set bits_per_word_mask so spi core will reject transfers that attempt to use an unsupported bits_per_word value. Also remove the duplicate code to test spi->mode, it is done by spi core. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-mpc52xx.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/spi/spi-mpc52xx.c b/drivers/spi/spi-mpc52xx.c index e3d29a56d70a..95bd2ffb0572 100644 --- a/drivers/spi/spi-mpc52xx.c +++ b/drivers/spi/spi-mpc52xx.c @@ -357,17 +357,6 @@ static void mpc52xx_spi_wq(struct work_struct *work) * spi_master ops */ -static int mpc52xx_spi_setup(struct spi_device *spi) -{ - if (spi->bits_per_word % 8) - return -EINVAL; - - if (spi->mode & ~(SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST)) - return -EINVAL; - - return 0; -} - static int mpc52xx_spi_transfer(struct spi_device *spi, struct spi_message *m) { struct mpc52xx_spi *ms = spi_master_get_devdata(spi->master); @@ -430,9 +419,9 @@ static int mpc52xx_spi_probe(struct platform_device *op) goto err_alloc; } - master->setup = mpc52xx_spi_setup; master->transfer = mpc52xx_spi_transfer; master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; + master->bits_per_word_mask = SPI_BPW_MASK(8); master->dev.of_node = op->dev.of_node; platform_set_drvdata(op, master); From d9721ae1493725bb14dcd1a3c19bbb5795e4a42f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Mar 2014 18:50:12 +0800 Subject: [PATCH 200/201] spi: bitbang: Make spi_bitbang_stop() return void spi_bitbang_stop() never fails, so make it return void. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/spi/spi-bitbang.c | 4 +--- drivers/spi/spi-butterfly.c | 3 +-- drivers/spi/spi-gpio.c | 5 ++--- drivers/spi/spi-omap-uwire.c | 5 ++--- include/linux/spi/spi_bitbang.h | 2 +- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c index bd222f6b677d..67aead248753 100644 --- a/drivers/spi/spi-bitbang.c +++ b/drivers/spi/spi-bitbang.c @@ -467,11 +467,9 @@ EXPORT_SYMBOL_GPL(spi_bitbang_start); /** * spi_bitbang_stop - stops the task providing spi communication */ -int spi_bitbang_stop(struct spi_bitbang *bitbang) +void spi_bitbang_stop(struct spi_bitbang *bitbang) { spi_unregister_master(bitbang->master); - - return 0; } EXPORT_SYMBOL_GPL(spi_bitbang_stop); diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c index 8081f96bd1d5..ee4f91ccd8fd 100644 --- a/drivers/spi/spi-butterfly.c +++ b/drivers/spi/spi-butterfly.c @@ -309,7 +309,6 @@ done: static void butterfly_detach(struct parport *p) { struct butterfly *pp; - int status; /* FIXME this global is ugly ... but, how to quickly get from * the parport to the "struct butterfly" associated with it? @@ -321,7 +320,7 @@ static void butterfly_detach(struct parport *p) butterfly = NULL; /* stop() unregisters child devices too */ - status = spi_bitbang_stop(&pp->bitbang); + spi_bitbang_stop(&pp->bitbang); /* turn off VCC */ parport_write_data(pp->port, 0); diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c index 7beeb29472ac..b189b958432b 100644 --- a/drivers/spi/spi-gpio.c +++ b/drivers/spi/spi-gpio.c @@ -503,13 +503,12 @@ static int spi_gpio_remove(struct platform_device *pdev) { struct spi_gpio *spi_gpio; struct spi_gpio_platform_data *pdata; - int status; spi_gpio = platform_get_drvdata(pdev); pdata = dev_get_platdata(&pdev->dev); /* stop() unregisters child devices too */ - status = spi_bitbang_stop(&spi_gpio->bitbang); + spi_bitbang_stop(&spi_gpio->bitbang); if (SPI_MISO_GPIO != SPI_GPIO_NO_MISO) gpio_free(SPI_MISO_GPIO); @@ -518,7 +517,7 @@ static int spi_gpio_remove(struct platform_device *pdev) gpio_free(SPI_SCK_GPIO); spi_master_put(spi_gpio->bitbang.master); - return status; + return 0; } MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c index 9313fd3b413d..a4d7bb557792 100644 --- a/drivers/spi/spi-omap-uwire.c +++ b/drivers/spi/spi-omap-uwire.c @@ -539,14 +539,13 @@ static int uwire_probe(struct platform_device *pdev) static int uwire_remove(struct platform_device *pdev) { struct uwire_spi *uwire = platform_get_drvdata(pdev); - int status; // FIXME remove all child devices, somewhere ... - status = spi_bitbang_stop(&uwire->bitbang); + spi_bitbang_stop(&uwire->bitbang); uwire_off(uwire); iounmap(uwire_base); - return status; + return 0; } /* work with hotplug and coldplug */ diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index daebaba886aa..85578d4be034 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -42,6 +42,6 @@ extern int spi_bitbang_setup_transfer(struct spi_device *spi, /* start or stop queue processing */ extern int spi_bitbang_start(struct spi_bitbang *spi); -extern int spi_bitbang_stop(struct spi_bitbang *spi); +extern void spi_bitbang_stop(struct spi_bitbang *spi); #endif /* __SPI_BITBANG_H */ From 0b73aa63c193006c3d503d4903dd4792a26e1d50 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Sat, 29 Mar 2014 23:48:07 +0000 Subject: [PATCH 201/201] spi: Fix handling of cs_change in core implementation The core implementation of cs_change didn't follow the documentation which says that cs_change in the middle of the transfer means to briefly deassert chip select, instead it followed buggy drivers which change the polarity of chip select. Use a delay of 10us between deassert and reassert simply from pulling numbers out of a hat. Reported-by: Gerhard Sittig Signed-off-by: Mark Brown --- drivers/spi/spi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 23756b0f9036..5d826f047714 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -591,7 +591,6 @@ static int spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { struct spi_transfer *xfer; - bool cur_cs = true; bool keep_cs = false; int ret = 0; @@ -627,8 +626,9 @@ static int spi_transfer_one_message(struct spi_master *master, &msg->transfers)) { keep_cs = true; } else { - cur_cs = !cur_cs; - spi_set_cs(msg->spi, cur_cs); + spi_set_cs(msg->spi, false); + udelay(10); + spi_set_cs(msg->spi, true); } }