aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/spi/atmel_spi.c127
1 files changed, 103 insertions, 24 deletions
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 01ad6320d96c..ad144054da30 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -46,6 +46,7 @@ struct atmel_spi {
46 struct clk *clk; 46 struct clk *clk;
47 struct platform_device *pdev; 47 struct platform_device *pdev;
48 unsigned new_1:1; 48 unsigned new_1:1;
49 struct spi_device *stay;
49 50
50 u8 stopping; 51 u8 stopping;
51 struct list_head queue; 52 struct list_head queue;
@@ -62,29 +63,62 @@ struct atmel_spi {
62/* 63/*
63 * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby 64 * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
64 * they assume that spi slave device state will not change on deselect, so 65 * they assume that spi slave device state will not change on deselect, so
65 * that automagic deselection is OK. Not so! Workaround uses nCSx pins 66 * that automagic deselection is OK. ("NPCSx rises if no data is to be
66 * as GPIOs; or newer controllers have CSAAT and friends. 67 * transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer
68 * controllers have CSAAT and friends.
67 * 69 *
68 * Since the CSAAT functionality is a bit weird on newer controllers 70 * Since the CSAAT functionality is a bit weird on newer controllers as
69 * as well, we use GPIO to control nCSx pins on all controllers. 71 * well, we use GPIO to control nCSx pins on all controllers, updating
72 * MR.PCS to avoid confusing the controller. Using GPIOs also lets us
73 * support active-high chipselects despite the controller's belief that
74 * only active-low devices/systems exists.
75 *
76 * However, at91rm9200 has a second erratum whereby nCS0 doesn't work
77 * right when driven with GPIO. ("Mode Fault does not allow more than one
78 * Master on Chip Select 0.") No workaround exists for that ... so for
79 * nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH,
80 * and (c) will trigger that first erratum in some cases.
70 */ 81 */
71 82
72static inline void cs_activate(struct spi_device *spi) 83static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
73{ 84{
74 unsigned gpio = (unsigned) spi->controller_data; 85 unsigned gpio = (unsigned) spi->controller_data;
75 unsigned active = spi->mode & SPI_CS_HIGH; 86 unsigned active = spi->mode & SPI_CS_HIGH;
87 u32 mr;
88
89 mr = spi_readl(as, MR);
90 mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr);
91
92 dev_dbg(&spi->dev, "activate %u%s, mr %08x\n",
93 gpio, active ? " (high)" : "",
94 mr);
76 95
77 dev_dbg(&spi->dev, "activate %u%s\n", gpio, active ? " (high)" : ""); 96 if (!(cpu_is_at91rm9200() && spi->chip_select == 0))
78 gpio_set_value(gpio, active); 97 gpio_set_value(gpio, active);
98 spi_writel(as, MR, mr);
79} 99}
80 100
81static inline void cs_deactivate(struct spi_device *spi) 101static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
82{ 102{
83 unsigned gpio = (unsigned) spi->controller_data; 103 unsigned gpio = (unsigned) spi->controller_data;
84 unsigned active = spi->mode & SPI_CS_HIGH; 104 unsigned active = spi->mode & SPI_CS_HIGH;
105 u32 mr;
85 106
86 dev_dbg(&spi->dev, "DEactivate %u%s\n", gpio, active ? " (low)" : ""); 107 /* only deactivate *this* device; sometimes transfers to
87 gpio_set_value(gpio, !active); 108 * another device may be active when this routine is called.
109 */
110 mr = spi_readl(as, MR);
111 if (~SPI_BFEXT(PCS, mr) & (1 << spi->chip_select)) {
112 mr = SPI_BFINS(PCS, 0xf, mr);
113 spi_writel(as, MR, mr);
114 }
115
116 dev_dbg(&spi->dev, "DEactivate %u%s, mr %08x\n",
117 gpio, active ? " (low)" : "",
118 mr);
119
120 if (!(cpu_is_at91rm9200() && spi->chip_select == 0))
121 gpio_set_value(gpio, !active);
88} 122}
89 123
90/* 124/*
@@ -140,6 +174,7 @@ static void atmel_spi_next_xfer(struct spi_master *master,
140 174
141 /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer" 175 /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
142 * mechanism might help avoid the IRQ latency between transfers 176 * mechanism might help avoid the IRQ latency between transfers
177 * (and improve the nCS0 errata handling on at91rm9200 chips)
143 * 178 *
144 * We're also waiting for ENDRX before we start the next 179 * We're also waiting for ENDRX before we start the next
145 * transfer because we need to handle some difficult timing 180 * transfer because we need to handle some difficult timing
@@ -169,17 +204,25 @@ static void atmel_spi_next_message(struct spi_master *master)
169{ 204{
170 struct atmel_spi *as = spi_master_get_devdata(master); 205 struct atmel_spi *as = spi_master_get_devdata(master);
171 struct spi_message *msg; 206 struct spi_message *msg;
172 u32 mr; 207 struct spi_device *spi;
173 208
174 BUG_ON(as->current_transfer); 209 BUG_ON(as->current_transfer);
175 210
176 msg = list_entry(as->queue.next, struct spi_message, queue); 211 msg = list_entry(as->queue.next, struct spi_message, queue);
212 spi = msg->spi;
177 213
178 /* Select the chip */ 214 dev_dbg(master->cdev.dev, "start message %p for %s\n",
179 mr = spi_readl(as, MR); 215 msg, spi->dev.bus_id);
180 mr = SPI_BFINS(PCS, ~(1 << msg->spi->chip_select), mr); 216
181 spi_writel(as, MR, mr); 217 /* select chip if it's not still active */
182 cs_activate(msg->spi); 218 if (as->stay) {
219 if (as->stay != spi) {
220 cs_deactivate(as, as->stay);
221 cs_activate(as, spi);
222 }
223 as->stay = NULL;
224 } else
225 cs_activate(as, spi);
183 226
184 atmel_spi_next_xfer(master, msg); 227 atmel_spi_next_xfer(master, msg);
185} 228}
@@ -232,9 +275,13 @@ static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
232 275
233static void 276static void
234atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, 277atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
235 struct spi_message *msg, int status) 278 struct spi_message *msg, int status, int stay)
236{ 279{
237 cs_deactivate(msg->spi); 280 if (!stay || status < 0)
281 cs_deactivate(as, msg->spi);
282 else
283 as->stay = msg->spi;
284
238 list_del(&msg->queue); 285 list_del(&msg->queue);
239 msg->status = status; 286 msg->status = status;
240 287
@@ -324,7 +371,7 @@ atmel_spi_interrupt(int irq, void *dev_id)
324 /* Clear any overrun happening while cleaning up */ 371 /* Clear any overrun happening while cleaning up */
325 spi_readl(as, SR); 372 spi_readl(as, SR);
326 373
327 atmel_spi_msg_done(master, as, msg, -EIO); 374 atmel_spi_msg_done(master, as, msg, -EIO, 0);
328 } else if (pending & SPI_BIT(ENDRX)) { 375 } else if (pending & SPI_BIT(ENDRX)) {
329 ret = IRQ_HANDLED; 376 ret = IRQ_HANDLED;
330 377
@@ -342,12 +389,13 @@ atmel_spi_interrupt(int irq, void *dev_id)
342 389
343 if (msg->transfers.prev == &xfer->transfer_list) { 390 if (msg->transfers.prev == &xfer->transfer_list) {
344 /* report completed message */ 391 /* report completed message */
345 atmel_spi_msg_done(master, as, msg, 0); 392 atmel_spi_msg_done(master, as, msg, 0,
393 xfer->cs_change);
346 } else { 394 } else {
347 if (xfer->cs_change) { 395 if (xfer->cs_change) {
348 cs_deactivate(msg->spi); 396 cs_deactivate(as, msg->spi);
349 udelay(1); 397 udelay(1);
350 cs_activate(msg->spi); 398 cs_activate(as, msg->spi);
351 } 399 }
352 400
353 /* 401 /*
@@ -410,6 +458,14 @@ static int atmel_spi_setup(struct spi_device *spi)
410 return -EINVAL; 458 return -EINVAL;
411 } 459 }
412 460
461 /* see notes above re chipselect */
462 if (cpu_is_at91rm9200()
463 && spi->chip_select == 0
464 && (spi->mode & SPI_CS_HIGH)) {
465 dev_dbg(&spi->dev, "setup: can't be active-high\n");
466 return -EINVAL;
467 }
468
413 /* speed zero convention is used by some upper layers */ 469 /* speed zero convention is used by some upper layers */
414 bus_hz = clk_get_rate(as->clk); 470 bus_hz = clk_get_rate(as->clk);
415 if (spi->max_speed_hz) { 471 if (spi->max_speed_hz) {
@@ -446,6 +502,14 @@ static int atmel_spi_setup(struct spi_device *spi)
446 return ret; 502 return ret;
447 spi->controller_state = (void *)npcs_pin; 503 spi->controller_state = (void *)npcs_pin;
448 gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); 504 gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH));
505 } else {
506 unsigned long flags;
507
508 spin_lock_irqsave(&as->lock, flags);
509 if (as->stay == spi)
510 as->stay = NULL;
511 cs_deactivate(as, spi);
512 spin_unlock_irqrestore(&as->lock, flags);
449 } 513 }
450 514
451 dev_dbg(&spi->dev, 515 dev_dbg(&spi->dev,
@@ -502,6 +566,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
502 } 566 }
503 } 567 }
504 568
569#ifdef VERBOSE
505 list_for_each_entry(xfer, &msg->transfers, transfer_list) { 570 list_for_each_entry(xfer, &msg->transfers, transfer_list) {
506 dev_dbg(controller, 571 dev_dbg(controller,
507 " xfer %p: len %u tx %p/%08x rx %p/%08x\n", 572 " xfer %p: len %u tx %p/%08x rx %p/%08x\n",
@@ -509,6 +574,7 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
509 xfer->tx_buf, xfer->tx_dma, 574 xfer->tx_buf, xfer->tx_dma,
510 xfer->rx_buf, xfer->rx_dma); 575 xfer->rx_buf, xfer->rx_dma);
511 } 576 }
577#endif
512 578
513 msg->status = -EINPROGRESS; 579 msg->status = -EINPROGRESS;
514 msg->actual_length = 0; 580 msg->actual_length = 0;
@@ -524,8 +590,21 @@ static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
524 590
525static void atmel_spi_cleanup(struct spi_device *spi) 591static void atmel_spi_cleanup(struct spi_device *spi)
526{ 592{
527 if (spi->controller_state) 593 struct atmel_spi *as = spi_master_get_devdata(spi->master);
528 gpio_free((unsigned int)spi->controller_data); 594 unsigned gpio = (unsigned) spi->controller_data;
595 unsigned long flags;
596
597 if (!spi->controller_state)
598 return;
599
600 spin_lock_irqsave(&as->lock, flags);
601 if (as->stay == spi) {
602 as->stay = NULL;
603 cs_deactivate(as, spi);
604 }
605 spin_unlock_irqrestore(&as->lock, flags);
606
607 gpio_free(gpio);
529} 608}
530 609
531/*-------------------------------------------------------------------------*/ 610/*-------------------------------------------------------------------------*/