aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-bcm63xx.c
diff options
context:
space:
mode:
authorFlorian Fainelli <florian@openwrt.org>2012-04-20 09:37:33 -0400
committerGrant Likely <grant.likely@secretlab.ca>2012-04-27 13:15:41 -0400
commitcde4384e1037c15e5dd04c68d19c75798b6281dd (patch)
treed3b9865bdb5d064c9f047310acd6588091f6d8cd /drivers/spi/spi-bcm63xx.c
parentd4b9b578cba7231c1fbafbe901a2e8f38654e056 (diff)
spi/bcm63xx: convert to the pump message infrastructure
This patch converts the bcm63xx SPI driver to use the SPI infrastructure pump message queue. Since we were previously sleeping in the SPI driver's transfer() function (which is not allowed) this is now fixed as well. To complete that conversion a certain number of changes have been made: - the transfer len is split into multiple hardware transfers in case its size is bigger than the hardware FIFO size - the FIFO refill is no longer done in the interrupt context, which was a bad idea leading to quick interrupt handler re-entrancy Tested-by: Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com> Signed-off-by: Florian Fainelli <florian@openwrt.org> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi/spi-bcm63xx.c')
-rw-r--r--drivers/spi/spi-bcm63xx.c149
1 files changed, 89 insertions, 60 deletions
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index f01b2648452e..63b0028a8bd3 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * Broadcom BCM63xx SPI controller support 2 * Broadcom BCM63xx SPI controller support
3 * 3 *
4 * Copyright (C) 2009-2011 Florian Fainelli <florian@openwrt.org> 4 * Copyright (C) 2009-2012 Florian Fainelli <florian@openwrt.org>
5 * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com> 5 * Copyright (C) 2010 Tanguy Bouzeloc <tanguy.bouzeloc@efixo.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
@@ -30,6 +30,8 @@
30#include <linux/spi/spi.h> 30#include <linux/spi/spi.h>
31#include <linux/completion.h> 31#include <linux/completion.h>
32#include <linux/err.h> 32#include <linux/err.h>
33#include <linux/workqueue.h>
34#include <linux/pm_runtime.h>
33 35
34#include <bcm63xx_dev_spi.h> 36#include <bcm63xx_dev_spi.h>
35 37
@@ -96,17 +98,12 @@ static const unsigned bcm63xx_spi_freq_table[SPI_CLK_MASK][2] = {
96 { 391000, SPI_CLK_0_391MHZ } 98 { 391000, SPI_CLK_0_391MHZ }
97}; 99};
98 100
99static int bcm63xx_spi_setup_transfer(struct spi_device *spi, 101static int bcm63xx_spi_check_transfer(struct spi_device *spi,
100 struct spi_transfer *t) 102 struct spi_transfer *t)
101{ 103{
102 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
103 u8 bits_per_word; 104 u8 bits_per_word;
104 u8 clk_cfg, reg;
105 u32 hz;
106 int i;
107 105
108 bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word; 106 bits_per_word = (t) ? t->bits_per_word : spi->bits_per_word;
109 hz = (t) ? t->speed_hz : spi->max_speed_hz;
110 if (bits_per_word != 8) { 107 if (bits_per_word != 8) {
111 dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n", 108 dev_err(&spi->dev, "%s, unsupported bits_per_word=%d\n",
112 __func__, bits_per_word); 109 __func__, bits_per_word);
@@ -119,6 +116,19 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
119 return -EINVAL; 116 return -EINVAL;
120 } 117 }
121 118
119 return 0;
120}
121
122static void bcm63xx_spi_setup_transfer(struct spi_device *spi,
123 struct spi_transfer *t)
124{
125 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
126 u32 hz;
127 u8 clk_cfg, reg;
128 int i;
129
130 hz = (t) ? t->speed_hz : spi->max_speed_hz;
131
122 /* Find the closest clock configuration */ 132 /* Find the closest clock configuration */
123 for (i = 0; i < SPI_CLK_MASK; i++) { 133 for (i = 0; i < SPI_CLK_MASK; i++) {
124 if (hz <= bcm63xx_spi_freq_table[i][0]) { 134 if (hz <= bcm63xx_spi_freq_table[i][0]) {
@@ -139,8 +149,6 @@ static int bcm63xx_spi_setup_transfer(struct spi_device *spi,
139 bcm_spi_writeb(bs, reg, SPI_CLK_CFG); 149 bcm_spi_writeb(bs, reg, SPI_CLK_CFG);
140 dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n", 150 dev_dbg(&spi->dev, "Setting clock register to %02x (hz %d)\n",
141 clk_cfg, hz); 151 clk_cfg, hz);
142
143 return 0;
144} 152}
145 153
146/* the spi->mode bits understood by this driver: */ 154/* the spi->mode bits understood by this driver: */
@@ -165,7 +173,7 @@ static int bcm63xx_spi_setup(struct spi_device *spi)
165 return -EINVAL; 173 return -EINVAL;
166 } 174 }
167 175
168 ret = bcm63xx_spi_setup_transfer(spi, NULL); 176 ret = bcm63xx_spi_check_transfer(spi, NULL);
169 if (ret < 0) { 177 if (ret < 0) {
170 dev_err(&spi->dev, "setup: unsupported mode bits %x\n", 178 dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
171 spi->mode & ~MODEBITS); 179 spi->mode & ~MODEBITS);
@@ -190,28 +198,29 @@ static void bcm63xx_spi_fill_tx_fifo(struct bcm63xx_spi *bs)
190 bs->remaining_bytes -= size; 198 bs->remaining_bytes -= size;
191} 199}
192 200
193static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t) 201static unsigned int bcm63xx_txrx_bufs(struct spi_device *spi,
202 struct spi_transfer *t)
194{ 203{
195 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); 204 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master);
196 u16 msg_ctl; 205 u16 msg_ctl;
197 u16 cmd; 206 u16 cmd;
198 207
208 /* Disable the CMD_DONE interrupt */
209 bcm_spi_writeb(bs, 0, SPI_INT_MASK);
210
199 dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n", 211 dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
200 t->tx_buf, t->rx_buf, t->len); 212 t->tx_buf, t->rx_buf, t->len);
201 213
202 /* Transmitter is inhibited */ 214 /* Transmitter is inhibited */
203 bs->tx_ptr = t->tx_buf; 215 bs->tx_ptr = t->tx_buf;
204 bs->rx_ptr = t->rx_buf; 216 bs->rx_ptr = t->rx_buf;
205 init_completion(&bs->done);
206 217
207 if (t->tx_buf) { 218 if (t->tx_buf) {
208 bs->remaining_bytes = t->len; 219 bs->remaining_bytes = t->len;
209 bcm63xx_spi_fill_tx_fifo(bs); 220 bcm63xx_spi_fill_tx_fifo(bs);
210 } 221 }
211 222
212 /* Enable the command done interrupt which 223 init_completion(&bs->done);
213 * we use to determine completion of a command */
214 bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
215 224
216 /* Fill in the Message control register */ 225 /* Fill in the Message control register */
217 msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT); 226 msg_ctl = (t->len << SPI_BYTE_CNT_SHIFT);
@@ -230,33 +239,76 @@ static int bcm63xx_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
230 cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT); 239 cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
231 cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT); 240 cmd |= (spi->chip_select << SPI_CMD_DEVICE_ID_SHIFT);
232 bcm_spi_writew(bs, cmd, SPI_CMD); 241 bcm_spi_writew(bs, cmd, SPI_CMD);
233 wait_for_completion(&bs->done);
234 242
235 /* Disable the CMD_DONE interrupt */ 243 /* Enable the CMD_DONE interrupt */
236 bcm_spi_writeb(bs, 0, SPI_INT_MASK); 244 bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
237 245
238 return t->len - bs->remaining_bytes; 246 return t->len - bs->remaining_bytes;
239} 247}
240 248
241static int bcm63xx_transfer(struct spi_device *spi, struct spi_message *m) 249static int bcm63xx_spi_prepare_transfer(struct spi_master *master)
242{ 250{
243 struct bcm63xx_spi *bs = spi_master_get_devdata(spi->master); 251 struct bcm63xx_spi *bs = spi_master_get_devdata(master);
244 struct spi_transfer *t;
245 int ret = 0;
246 252
247 if (unlikely(list_empty(&m->transfers))) 253 pm_runtime_get_sync(&bs->pdev->dev);
248 return -EINVAL;
249 254
250 if (bs->stopping) 255 return 0;
251 return -ESHUTDOWN; 256}
257
258static int bcm63xx_spi_unprepare_transfer(struct spi_master *master)
259{
260 struct bcm63xx_spi *bs = spi_master_get_devdata(master);
261
262 pm_runtime_put(&bs->pdev->dev);
263
264 return 0;
265}
266
267static int bcm63xx_spi_transfer_one(struct spi_master *master,
268 struct spi_message *m)
269{
270 struct bcm63xx_spi *bs = spi_master_get_devdata(master);
271 struct spi_transfer *t;
272 struct spi_device *spi = m->spi;
273 int status = 0;
274 unsigned int timeout = 0;
252 275
253 list_for_each_entry(t, &m->transfers, transfer_list) { 276 list_for_each_entry(t, &m->transfers, transfer_list) {
254 ret += bcm63xx_txrx_bufs(spi, t); 277 unsigned int len = t->len;
255 } 278 u8 rx_tail;
256 279
257 m->complete(m->context); 280 status = bcm63xx_spi_check_transfer(spi, t);
281 if (status < 0)
282 goto exit;
258 283
259 return ret; 284 /* configure adapter for a new transfer */
285 bcm63xx_spi_setup_transfer(spi, t);
286
287 while (len) {
288 /* send the data */
289 len -= bcm63xx_txrx_bufs(spi, t);
290
291 timeout = wait_for_completion_timeout(&bs->done, HZ);
292 if (!timeout) {
293 status = -ETIMEDOUT;
294 goto exit;
295 }
296
297 /* read out all data */
298 rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
299
300 /* Read out all the data */
301 if (rx_tail)
302 memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
303 }
304
305 m->actual_length += t->len;
306 }
307exit:
308 m->status = status;
309 spi_finalize_current_message(master);
310
311 return 0;
260} 312}
261 313
262/* This driver supports single master mode only. Hence 314/* This driver supports single master mode only. Hence
@@ -267,39 +319,15 @@ static irqreturn_t bcm63xx_spi_interrupt(int irq, void *dev_id)
267 struct spi_master *master = (struct spi_master *)dev_id; 319 struct spi_master *master = (struct spi_master *)dev_id;
268 struct bcm63xx_spi *bs = spi_master_get_devdata(master); 320 struct bcm63xx_spi *bs = spi_master_get_devdata(master);
269 u8 intr; 321 u8 intr;
270 u16 cmd;
271 322
272 /* Read interupts and clear them immediately */ 323 /* Read interupts and clear them immediately */
273 intr = bcm_spi_readb(bs, SPI_INT_STATUS); 324 intr = bcm_spi_readb(bs, SPI_INT_STATUS);
274 bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS); 325 bcm_spi_writeb(bs, SPI_INTR_CLEAR_ALL, SPI_INT_STATUS);
275 bcm_spi_writeb(bs, 0, SPI_INT_MASK); 326 bcm_spi_writeb(bs, 0, SPI_INT_MASK);
276 327
277 /* A tansfer completed */ 328 /* A transfer completed */
278 if (intr & SPI_INTR_CMD_DONE) { 329 if (intr & SPI_INTR_CMD_DONE)
279 u8 rx_tail; 330 complete(&bs->done);
280
281 rx_tail = bcm_spi_readb(bs, SPI_RX_TAIL);
282
283 /* Read out all the data */
284 if (rx_tail)
285 memcpy_fromio(bs->rx_ptr, bs->rx_io, rx_tail);
286
287 /* See if there is more data to send */
288 if (bs->remaining_bytes > 0) {
289 bcm63xx_spi_fill_tx_fifo(bs);
290
291 /* Start the transfer */
292 bcm_spi_writew(bs, SPI_HD_W << SPI_MSG_TYPE_SHIFT,
293 SPI_MSG_CTL);
294 cmd = bcm_spi_readw(bs, SPI_CMD);
295 cmd |= SPI_CMD_START_IMMEDIATE;
296 cmd |= (0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT);
297 bcm_spi_writeb(bs, SPI_INTR_CMD_DONE, SPI_INT_MASK);
298 bcm_spi_writew(bs, cmd, SPI_CMD);
299 } else {
300 complete(&bs->done);
301 }
302 }
303 331
304 return IRQ_HANDLED; 332 return IRQ_HANDLED;
305} 333}
@@ -345,7 +373,6 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
345 } 373 }
346 374
347 bs = spi_master_get_devdata(master); 375 bs = spi_master_get_devdata(master);
348 init_completion(&bs->done);
349 376
350 platform_set_drvdata(pdev, master); 377 platform_set_drvdata(pdev, master);
351 bs->pdev = pdev; 378 bs->pdev = pdev;
@@ -379,7 +406,9 @@ static int __devinit bcm63xx_spi_probe(struct platform_device *pdev)
379 master->bus_num = pdata->bus_num; 406 master->bus_num = pdata->bus_num;
380 master->num_chipselect = pdata->num_chipselect; 407 master->num_chipselect = pdata->num_chipselect;
381 master->setup = bcm63xx_spi_setup; 408 master->setup = bcm63xx_spi_setup;
382 master->transfer = bcm63xx_transfer; 409 master->prepare_transfer_hardware = bcm63xx_spi_prepare_transfer;
410 master->unprepare_transfer_hardware = bcm63xx_spi_unprepare_transfer;
411 master->transfer_one_message = bcm63xx_spi_transfer_one;
383 bs->speed_hz = pdata->speed_hz; 412 bs->speed_hz = pdata->speed_hz;
384 bs->stopping = 0; 413 bs->stopping = 0;
385 bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA)); 414 bs->tx_io = (u8 *)(bs->regs + bcm63xx_spireg(SPI_MSG_DATA));