diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/input/touchscreen/ads7846.c | 12 | ||||
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 50 | ||||
-rw-r--r-- | drivers/mtd/devices/mtd_dataflash.c | 28 | ||||
-rw-r--r-- | drivers/spi/spi.c | 18 | ||||
-rw-r--r-- | drivers/spi/spi_bitbang.c | 86 |
5 files changed, 110 insertions, 84 deletions
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index c741776ef3bf..dd8c6a9ffc76 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -155,10 +155,13 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) struct ser_req *req = kzalloc(sizeof *req, SLAB_KERNEL); int status; int sample; + int i; if (!req) return -ENOMEM; + INIT_LIST_HEAD(&req->msg.transfers); + /* activate reference, so it has time to settle; */ req->xfer[0].tx_buf = &ref_on; req->xfer[0].len = 1; @@ -192,8 +195,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) /* group all the transfers together, so we can't interfere with * reading touchscreen state; disable penirq while sampling */ - req->msg.transfers = req->xfer; - req->msg.n_transfer = 6; + for (i = 0; i < 6; i++) + spi_message_add_tail(&req->xfer[i], &req->msg); disable_irq(spi->irq); status = spi_sync(spi, &req->msg); @@ -398,6 +401,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) struct ads7846 *ts; struct ads7846_platform_data *pdata = spi->dev.platform_data; struct spi_transfer *x; + int i; if (!spi->irq) { dev_dbg(&spi->dev, "no IRQ?\n"); @@ -500,8 +504,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) CS_CHANGE(x[-1]); - ts->msg.transfers = ts->xfer; - ts->msg.n_transfer = x - ts->xfer; + for (i = 0; i < x - ts->xfer; i++) + spi_message_add_tail(&ts->xfer[i], &ts->msg); ts->msg.complete = ads7846_rx; ts->msg.context = ts; diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 71a072103a7f..45108ed85588 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -245,6 +245,21 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, if (from + len > flash->mtd.size) return -EINVAL; + spi_message_init(&m); + memset(t, 0, (sizeof t)); + + t[0].tx_buf = flash->command; + t[0].len = sizeof(flash->command); + spi_message_add_tail(&t[0], &m); + + t[1].rx_buf = buf; + t[1].len = len; + spi_message_add_tail(&t[1], &m); + + /* Byte count starts at zero. */ + if (retlen) + *retlen = 0; + down(&flash->lock); /* Wait till previous write/erase is done. */ @@ -254,8 +269,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, return 1; } - memset(t, 0, (sizeof t)); - /* NOTE: OPCODE_FAST_READ (if available) is faster... */ /* Set up the write data buffer. */ @@ -264,19 +277,6 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len, flash->command[2] = from >> 8; flash->command[3] = from; - /* Byte count starts at zero. */ - if (retlen) - *retlen = 0; - - t[0].tx_buf = flash->command; - t[0].len = sizeof(flash->command); - - t[1].rx_buf = buf; - t[1].len = len; - - m.transfers = t; - m.n_transfer = 2; - spi_sync(flash->spi, &m); *retlen = m.actual_length - sizeof(flash->command); @@ -313,6 +313,16 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, if (to + len > flash->mtd.size) return -EINVAL; + spi_message_init(&m); + memset(t, 0, (sizeof t)); + + t[0].tx_buf = flash->command; + t[0].len = sizeof(flash->command); + spi_message_add_tail(&t[0], &m); + + t[1].tx_buf = buf; + spi_message_add_tail(&t[1], &m); + down(&flash->lock); /* Wait until finished previous write command. */ @@ -321,26 +331,17 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, write_enable(flash); - memset(t, 0, (sizeof t)); - /* Set up the opcode in the write buffer. */ flash->command[0] = OPCODE_PP; flash->command[1] = to >> 16; flash->command[2] = to >> 8; flash->command[3] = to; - t[0].tx_buf = flash->command; - t[0].len = sizeof(flash->command); - - m.transfers = t; - m.n_transfer = 2; - /* what page do we start with? */ page_offset = to % FLASH_PAGESIZE; /* do all the bytes fit onto one page? */ if (page_offset + len <= FLASH_PAGESIZE) { - t[1].tx_buf = buf; t[1].len = len; spi_sync(flash->spi, &m); @@ -352,7 +353,6 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, /* the size of data remaining on the first page */ page_size = FLASH_PAGESIZE - page_offset; - t[1].tx_buf = buf; t[1].len = page_size; spi_sync(flash->spi, &m); diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c index a39b3b6b266c..99d3a0320fc9 100644 --- a/drivers/mtd/devices/mtd_dataflash.c +++ b/drivers/mtd/devices/mtd_dataflash.c @@ -147,7 +147,7 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) { struct dataflash *priv = (struct dataflash *)mtd->priv; struct spi_device *spi = priv->spi; - struct spi_transfer x[1] = { { .tx_dma = 0, }, }; + struct spi_transfer x = { .tx_dma = 0, }; struct spi_message msg; unsigned blocksize = priv->page_size << 3; u8 *command; @@ -162,10 +162,11 @@ static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) || (instr->addr % priv->page_size) != 0) return -EINVAL; - x[0].tx_buf = command = priv->command; - x[0].len = 4; - msg.transfers = x; - msg.n_transfer = 1; + spi_message_init(&msg); + + x.tx_buf = command = priv->command; + x.len = 4; + spi_message_add_tail(&x, &msg); down(&priv->lock); while (instr->len > 0) { @@ -256,12 +257,15 @@ static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); + spi_message_init(&msg); + x[0].tx_buf = command; x[0].len = 8; + spi_message_add_tail(&x[0], &msg); + x[1].rx_buf = buf; x[1].len = len; - msg.transfers = x; - msg.n_transfer = 2; + spi_message_add_tail(&x[1], &msg); down(&priv->lock); @@ -320,9 +324,11 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, if ((to + len) > mtd->size) return -EINVAL; + spi_message_init(&msg); + x[0].tx_buf = command = priv->command; x[0].len = 4; - msg.transfers = x; + spi_message_add_tail(&x[0], &msg); pageaddr = ((unsigned)to / priv->page_size); offset = ((unsigned)to % priv->page_size); @@ -364,7 +370,6 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); - msg.n_transfer = 1; status = spi_sync(spi, &msg); if (status < 0) DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n", @@ -385,14 +390,16 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, x[1].tx_buf = writebuf; x[1].len = writelen; - msg.n_transfer = 2; + spi_message_add_tail(x + 1, &msg); status = spi_sync(spi, &msg); + spi_transfer_del(x + 1); if (status < 0) DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n", spi->dev.bus_id, addr, writelen, status); (void) dataflash_waitready(priv->spi); + #ifdef CONFIG_DATAFLASH_WRITE_VERIFY /* (3) Compare to Buffer1 */ @@ -405,7 +412,6 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]); - msg.n_transfer = 1; status = spi_sync(spi, &msg); if (status < 0) DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n", diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 3ecedccdb96c..cdb242de901d 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -557,6 +557,17 @@ int spi_write_then_read(struct spi_device *spi, if ((n_tx + n_rx) > SPI_BUFSIZ) return -EINVAL; + spi_message_init(&message); + memset(x, 0, sizeof x); + if (n_tx) { + x[0].len = n_tx; + spi_message_add_tail(&x[0], &message); + } + if (n_rx) { + x[1].len = n_rx; + spi_message_add_tail(&x[1], &message); + } + /* ... unless someone else is using the pre-allocated buffer */ if (down_trylock(&lock)) { local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); @@ -565,18 +576,11 @@ int spi_write_then_read(struct spi_device *spi, } else local_buf = buf; - memset(x, 0, sizeof x); - memcpy(local_buf, txbuf, n_tx); x[0].tx_buf = local_buf; - x[0].len = n_tx; - x[1].rx_buf = local_buf + n_tx; - x[1].len = n_rx; /* do the i/o */ - message.transfers = x; - message.n_transfer = ARRAY_SIZE(x); status = spi_sync(spi, &message); if (status == 0) { memcpy(rxbuf, x[1].rx_buf, n_rx); diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 44aff198eb96..f037e5593269 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -146,6 +146,9 @@ int spi_bitbang_setup(struct spi_device *spi) struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang *bitbang; + if (!spi->max_speed_hz) + return -EINVAL; + if (!cs) { cs = kzalloc(sizeof *cs, SLAB_KERNEL); if (!cs) @@ -172,13 +175,8 @@ int spi_bitbang_setup(struct spi_device *spi) if (!cs->txrx_word) return -EINVAL; - if (!spi->max_speed_hz) - spi->max_speed_hz = 500 * 1000; - - /* nsecs = max(50, (clock period)/2), be optimistic */ + /* nsecs = (clock period)/2 */ cs->nsecs = (1000000000/2) / (spi->max_speed_hz); - if (cs->nsecs < 50) - cs->nsecs = 50; if (cs->nsecs > MAX_UDELAY_MS * 1000) return -EINVAL; @@ -194,7 +192,7 @@ int spi_bitbang_setup(struct spi_device *spi) /* deselect chip (low or high) */ spin_lock(&bitbang->lock); if (!bitbang->busy) { - bitbang->chipselect(spi, 0); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); ndelay(cs->nsecs); } spin_unlock(&bitbang->lock); @@ -244,9 +242,9 @@ static void bitbang_work(void *_bitbang) struct spi_message *m; struct spi_device *spi; unsigned nsecs; - struct spi_transfer *t; + struct spi_transfer *t = NULL; unsigned tmp; - unsigned chipselect; + unsigned cs_change; int status; m = container_of(bitbang->queue.next, struct spi_message, @@ -254,37 +252,49 @@ static void bitbang_work(void *_bitbang) list_del_init(&m->queue); spin_unlock_irqrestore(&bitbang->lock, flags); -// FIXME this is made-up -nsecs = 100; + /* FIXME this is made-up ... the correct value is known to + * word-at-a-time bitbang code, and presumably chipselect() + * should enforce these requirements too? + */ + nsecs = 100; spi = m->spi; - t = m->transfers; tmp = 0; - chipselect = 0; + cs_change = 1; status = 0; - for (;;t++) { + list_for_each_entry (t, &m->transfers, transfer_list) { if (bitbang->shutdown) { status = -ESHUTDOWN; break; } - /* set up default clock polarity, and activate chip */ - if (!chipselect) { - bitbang->chipselect(spi, 1); + /* set up default clock polarity, and activate chip; + * this implicitly updates clock and spi modes as + * previously recorded for this device via setup(). + * (and also deselects any other chip that might be + * selected ...) + */ + if (cs_change) { + bitbang->chipselect(spi, BITBANG_CS_ACTIVE); ndelay(nsecs); } + cs_change = t->cs_change; if (!t->tx_buf && !t->rx_buf && t->len) { status = -EINVAL; break; } - /* transfer data */ + /* transfer data. the lower level code handles any + * new dma mappings it needs. our caller always gave + * us dma-safe buffers. + */ if (t->len) { - /* FIXME if bitbang->use_dma, dma_map_single() - * before the transfer, and dma_unmap_single() - * afterwards, for either or both buffers... + /* REVISIT dma API still needs a designated + * DMA_ADDR_INVALID; ~0 might be better. */ + if (!m->is_dma_mapped) + t->rx_dma = t->tx_dma = 0; status = bitbang->txrx_bufs(spi, t); } if (status != t->len) { @@ -299,29 +309,31 @@ nsecs = 100; if (t->delay_usecs) udelay(t->delay_usecs); - tmp++; - if (tmp >= m->n_transfer) - break; - - chipselect = !t->cs_change; - if (chipselect); + if (!cs_change) continue; + if (t->transfer_list.next == &m->transfers) + break; - bitbang->chipselect(spi, 0); - - /* REVISIT do we want the udelay here instead? */ - msleep(1); + /* sometimes a short mid-message deselect of the chip + * may be needed to terminate a mode or command + */ + ndelay(nsecs); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); } - tmp = m->n_transfer - 1; - tmp = m->transfers[tmp].cs_change; - m->status = status; m->complete(m->context); - ndelay(2 * nsecs); - bitbang->chipselect(spi, status == 0 && tmp); - ndelay(nsecs); + /* normally deactivate chipselect ... unless no error and + * cs_change has hinted that the next message will probably + * be for this chip too. + */ + if (!(status == 0 && cs_change)) { + ndelay(nsecs); + bitbang->chipselect(spi, BITBANG_CS_INACTIVE); + ndelay(nsecs); + } spin_lock_irqsave(&bitbang->lock, flags); } |