--- zzzz-none-000/linux-3.10.107/drivers/spi/spi-atmel.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/spi/spi-atmel.c 2021-02-04 17:41:59.000000000 +0000 @@ -9,7 +9,6 @@ */ #include -#include #include #include #include @@ -20,12 +19,13 @@ #include #include #include -#include #include #include #include #include +#include +#include /* SPI register offsets */ #define SPI_CR 0x0000 @@ -40,6 +40,8 @@ #define SPI_CSR1 0x0034 #define SPI_CSR2 0x0038 #define SPI_CSR3 0x003c +#define SPI_FMR 0x0040 +#define SPI_FLR 0x0044 #define SPI_VERSION 0x00fc #define SPI_RPR 0x0100 #define SPI_RCR 0x0104 @@ -61,6 +63,14 @@ #define SPI_SWRST_SIZE 1 #define SPI_LASTXFER_OFFSET 24 #define SPI_LASTXFER_SIZE 1 +#define SPI_TXFCLR_OFFSET 16 +#define SPI_TXFCLR_SIZE 1 +#define SPI_RXFCLR_OFFSET 17 +#define SPI_RXFCLR_SIZE 1 +#define SPI_FIFOEN_OFFSET 30 +#define SPI_FIFOEN_SIZE 1 +#define SPI_FIFODIS_OFFSET 31 +#define SPI_FIFODIS_SIZE 1 /* Bitfields in MR */ #define SPI_MSTR_OFFSET 0 @@ -113,6 +123,22 @@ #define SPI_TXEMPTY_SIZE 1 #define SPI_SPIENS_OFFSET 16 #define SPI_SPIENS_SIZE 1 +#define SPI_TXFEF_OFFSET 24 +#define SPI_TXFEF_SIZE 1 +#define SPI_TXFFF_OFFSET 25 +#define SPI_TXFFF_SIZE 1 +#define SPI_TXFTHF_OFFSET 26 +#define SPI_TXFTHF_SIZE 1 +#define SPI_RXFEF_OFFSET 27 +#define SPI_RXFEF_SIZE 1 +#define SPI_RXFFF_OFFSET 28 +#define SPI_RXFFF_SIZE 1 +#define SPI_RXFTHF_OFFSET 29 +#define SPI_RXFTHF_SIZE 1 +#define SPI_TXFPTEF_OFFSET 30 +#define SPI_TXFPTEF_SIZE 1 +#define SPI_RXFPTEF_OFFSET 31 +#define SPI_RXFPTEF_SIZE 1 /* Bitfields in CSR0 */ #define SPI_CPOL_OFFSET 0 @@ -156,6 +182,22 @@ #define SPI_TXTDIS_OFFSET 9 #define SPI_TXTDIS_SIZE 1 +/* Bitfields in FMR */ +#define SPI_TXRDYM_OFFSET 0 +#define SPI_TXRDYM_SIZE 2 +#define SPI_RXRDYM_OFFSET 4 +#define SPI_RXRDYM_SIZE 2 +#define SPI_TXFTHRES_OFFSET 16 +#define SPI_TXFTHRES_SIZE 6 +#define SPI_RXFTHRES_OFFSET 24 +#define SPI_RXFTHRES_SIZE 6 + +/* Bitfields in FLR */ +#define SPI_TXFL_OFFSET 0 +#define SPI_TXFL_SIZE 6 +#define SPI_RXFL_OFFSET 16 +#define SPI_RXFL_SIZE 6 + /* Constants for BITS */ #define SPI_BITS_8_BPT 0 #define SPI_BITS_9_BPT 1 @@ -166,29 +208,62 @@ #define SPI_BITS_14_BPT 6 #define SPI_BITS_15_BPT 7 #define SPI_BITS_16_BPT 8 +#define SPI_ONE_DATA 0 +#define SPI_TWO_DATA 1 +#define SPI_FOUR_DATA 2 /* Bit manipulation macros */ #define SPI_BIT(name) \ (1 << SPI_##name##_OFFSET) -#define SPI_BF(name,value) \ +#define SPI_BF(name, value) \ (((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET) -#define SPI_BFEXT(name,value) \ +#define SPI_BFEXT(name, value) \ (((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1)) -#define SPI_BFINS(name,value,old) \ - ( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \ - | SPI_BF(name,value)) +#define SPI_BFINS(name, value, old) \ + (((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \ + | SPI_BF(name, value)) /* Register access macros */ -#define spi_readl(port,reg) \ +#ifdef CONFIG_AVR32 +#define spi_readl(port, reg) \ __raw_readl((port)->regs + SPI_##reg) -#define spi_writel(port,reg,value) \ +#define spi_writel(port, reg, value) \ __raw_writel((value), (port)->regs + SPI_##reg) +#define spi_readw(port, reg) \ + __raw_readw((port)->regs + SPI_##reg) +#define spi_writew(port, reg, value) \ + __raw_writew((value), (port)->regs + SPI_##reg) + +#define spi_readb(port, reg) \ + __raw_readb((port)->regs + SPI_##reg) +#define spi_writeb(port, reg, value) \ + __raw_writeb((value), (port)->regs + SPI_##reg) +#else +#define spi_readl(port, reg) \ + readl_relaxed((port)->regs + SPI_##reg) +#define spi_writel(port, reg, value) \ + writel_relaxed((value), (port)->regs + SPI_##reg) + +#define spi_readw(port, reg) \ + readw_relaxed((port)->regs + SPI_##reg) +#define spi_writew(port, reg, value) \ + writew_relaxed((value), (port)->regs + SPI_##reg) + +#define spi_readb(port, reg) \ + readb_relaxed((port)->regs + SPI_##reg) +#define spi_writeb(port, reg, value) \ + writeb_relaxed((value), (port)->regs + SPI_##reg) +#endif /* use PIO for small transfers, avoiding DMA setup/teardown overhead and * cache operations; better heuristics consider wordsize and bitrate. */ #define DMA_MIN_BYTES 16 +#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000)) + +#define AUTOSUSPEND_TIMEOUT 2000 + struct atmel_spi_dma { struct dma_chan *chan_rx; struct dma_chan *chan_tx; @@ -220,17 +295,13 @@ int irq; struct clk *clk; struct platform_device *pdev; - struct spi_device *stay; - u8 stopping; - struct list_head queue; - struct tasklet_struct tasklet; struct spi_transfer *current_transfer; - unsigned long current_remaining_bytes; - struct spi_transfer *next_transfer; - unsigned long next_remaining_bytes; + int current_remaining_bytes; int done_status; + struct completion xfer_completion; + /* scratch buffer */ void *buffer; dma_addr_t buffer_dma; @@ -239,8 +310,14 @@ bool use_dma; bool use_pdc; + bool use_cs_gpios; /* dmaengine data */ struct atmel_spi_dma dma; + + bool keep_cs; + bool cs_active; + + u32 fifo_size; }; /* Controller-specific per-slave state */ @@ -311,7 +388,8 @@ } mr = spi_readl(as, MR); - gpio_set_value(asd->npcs_pin, active); + if (as->use_cs_gpios) + gpio_set_value(asd->npcs_pin, active); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; @@ -327,7 +405,7 @@ mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); - if (spi->chip_select != 0) + if (as->use_cs_gpios && spi->chip_select != 0) gpio_set_value(asd->npcs_pin, active); spi_writel(as, MR, mr); } @@ -356,16 +434,18 @@ asd->npcs_pin, active ? " (low)" : "", mr); - if (atmel_spi_is_v2(as) || spi->chip_select != 0) + if (!as->use_cs_gpios) + spi_writel(as, CR, SPI_BIT(LASTXFER)); + else if (atmel_spi_is_v2(as) || spi->chip_select != 0) gpio_set_value(asd->npcs_pin, !active); } -static void atmel_spi_lock(struct atmel_spi *as) +static void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock) { spin_lock_irqsave(&as->lock, as->flags); } -static void atmel_spi_unlock(struct atmel_spi *as) +static void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock) { spin_unlock_irqrestore(&as->lock, as->flags); } @@ -376,17 +456,6 @@ return as->use_dma && xfer->len >= DMA_MIN_BYTES; } -static inline int atmel_spi_xfer_is_last(struct spi_message *msg, - struct spi_transfer *xfer) -{ - return msg->transfers.prev == &xfer->transfer_list; -} - -static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer) -{ - return xfer->delay_usecs == 0 && !xfer->cs_change; -} - static int atmel_spi_dma_slave_config(struct atmel_spi *as, struct dma_slave_config *slave_config, u8 bits_per_word) @@ -407,6 +476,20 @@ slave_config->dst_maxburst = 1; slave_config->device_fc = false; + /* + * This driver uses fixed peripheral select mode (PS bit set to '0' in + * the Mode Register). + * So according to the datasheet, when FIFOs are available (and + * enabled), the Transmit FIFO operates in Multiple Data Mode. + * In this mode, up to 2 data, not 4, can be written into the Transmit + * Data Register in a single access. + * However, the first data has to be written into the lowest 16 bits and + * the second data into the highest 16 bits of the Transmit + * Data Register. For 8bit data (the most frequent case), it would + * require to rework tx_buf so each data would actualy fit 16 bits. + * So we'd rather write only one data at the time. Hence the transmit + * path works the same whether FIFOs are available (and enabled) or not. + */ slave_config->direction = DMA_MEM_TO_DEV; if (dmaengine_slave_config(as->dma.chan_tx, slave_config)) { dev_err(&as->pdev->dev, @@ -414,6 +497,14 @@ err = -EINVAL; } + /* + * This driver configures the spi controller for master mode (MSTR bit + * set to '1' in the Mode Register). + * So according to the datasheet, when FIFOs are available (and + * enabled), the Receive FIFO operates in Single Data Mode. + * So the receive path works the same whether FIFOs are available (and + * enabled) or not. + */ slave_config->direction = DMA_DEV_TO_MEM; if (dmaengine_slave_config(as->dma.chan_rx, slave_config)) { dev_err(&as->pdev->dev, @@ -424,38 +515,38 @@ return err; } -static bool filter(struct dma_chan *chan, void *slave) -{ - struct at_dma_slave *sl = slave; - - if (sl->dma_dev == chan->device->dev) { - chan->private = sl; - return true; - } else { - return false; - } -} - static int atmel_spi_configure_dma(struct atmel_spi *as) { - struct at_dma_slave *sdata = &as->dma.dma_slave; struct dma_slave_config slave_config; + struct device *dev = &as->pdev->dev; int err; - if (sdata && sdata->dma_dev) { - dma_cap_mask_t mask; - - /* Try to grab two DMA channels */ - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - as->dma.chan_tx = dma_request_channel(mask, filter, sdata); - if (as->dma.chan_tx) - as->dma.chan_rx = - dma_request_channel(mask, filter, sdata); + dma_cap_mask_t mask; + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + as->dma.chan_tx = dma_request_slave_channel_reason(dev, "tx"); + if (IS_ERR(as->dma.chan_tx)) { + err = PTR_ERR(as->dma.chan_tx); + if (err == -EPROBE_DEFER) { + dev_warn(dev, "no DMA channel available at the moment\n"); + return err; + } + dev_err(dev, + "DMA TX channel not available, SPI unable to use DMA\n"); + err = -EBUSY; + goto error; } - if (!as->dma.chan_rx || !as->dma.chan_tx) { - dev_err(&as->pdev->dev, - "DMA channel not available, SPI unable to use DMA\n"); + + /* + * No reason to check EPROBE_DEFER here since we have already requested + * tx channel. If it fails here, it's for another reason. + */ + as->dma.chan_rx = dma_request_slave_channel(dev, "rx"); + + if (!as->dma.chan_rx) { + dev_err(dev, + "DMA RX channel not available, SPI unable to use DMA\n"); err = -EBUSY; goto error; } @@ -472,7 +563,7 @@ error: if (as->dma.chan_rx) dma_release_channel(as->dma.chan_rx); - if (as->dma.chan_tx) + if (!IS_ERR(as->dma.chan_tx)) dma_release_channel(as->dma.chan_tx); return err; } @@ -480,11 +571,9 @@ static void atmel_spi_stop_dma(struct atmel_spi *as) { if (as->dma.chan_rx) - as->dma.chan_rx->device->device_control(as->dma.chan_rx, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(as->dma.chan_rx); if (as->dma.chan_tx) - as->dma.chan_tx->device->device_control(as->dma.chan_tx, - DMA_TERMINATE_ALL, 0); + dmaengine_terminate_all(as->dma.chan_tx); } static void atmel_spi_release_dma(struct atmel_spi *as) @@ -501,23 +590,20 @@ struct spi_master *master = data; struct atmel_spi *as = spi_master_get_devdata(master); - /* trigger SPI tasklet */ - tasklet_schedule(&as->tasklet); + complete(&as->xfer_completion); } /* - * Next transfer using PIO. - * lock is held, spi tasklet is blocked + * Next transfer using PIO without FIFO. */ -static void atmel_spi_next_xfer_pio(struct spi_master *master, - struct spi_transfer *xfer) +static void atmel_spi_next_xfer_single(struct spi_master *master, + struct spi_transfer *xfer) { struct atmel_spi *as = spi_master_get_devdata(master); + unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n"); - as->current_remaining_bytes = xfer->len; - /* Make sure data is not remaining in RDR */ spi_readl(as, RDR); while (spi_readl(as, SR) & SPI_BIT(RDRF)) { @@ -525,13 +611,14 @@ cpu_relax(); } - if (xfer->tx_buf) + if (xfer->tx_buf) { if (xfer->bits_per_word > 8) - spi_writel(as, TDR, *(u16 *)(xfer->tx_buf)); + spi_writel(as, TDR, *(u16 *)(xfer->tx_buf + xfer_pos)); else - spi_writel(as, TDR, *(u8 *)(xfer->tx_buf)); - else + spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos)); + } else { spi_writel(as, TDR, 0); + } dev_dbg(master->dev.parent, " start pio xfer %p: len %u tx %p rx %p bitpw %d\n", @@ -543,8 +630,100 @@ } /* + * Next transfer using PIO with FIFO. + */ +static void atmel_spi_next_xfer_fifo(struct spi_master *master, + struct spi_transfer *xfer) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + u32 current_remaining_data, num_data; + u32 offset = xfer->len - as->current_remaining_bytes; + const u16 *words = (const u16 *)((u8 *)xfer->tx_buf + offset); + const u8 *bytes = (const u8 *)((u8 *)xfer->tx_buf + offset); + u16 td0, td1; + u32 fifomr; + + dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_fifo\n"); + + /* Compute the number of data to transfer in the current iteration */ + current_remaining_data = ((xfer->bits_per_word > 8) ? + ((u32)as->current_remaining_bytes >> 1) : + (u32)as->current_remaining_bytes); + num_data = min(current_remaining_data, as->fifo_size); + + /* Flush RX and TX FIFOs */ + spi_writel(as, CR, SPI_BIT(RXFCLR) | SPI_BIT(TXFCLR)); + while (spi_readl(as, FLR)) + cpu_relax(); + + /* Set RX FIFO Threshold to the number of data to transfer */ + fifomr = spi_readl(as, FMR); + spi_writel(as, FMR, SPI_BFINS(RXFTHRES, num_data, fifomr)); + + /* Clear FIFO flags in the Status Register, especially RXFTHF */ + (void)spi_readl(as, SR); + + /* Fill TX FIFO */ + while (num_data >= 2) { + if (xfer->tx_buf) { + if (xfer->bits_per_word > 8) { + td0 = *words++; + td1 = *words++; + } else { + td0 = *bytes++; + td1 = *bytes++; + } + } else { + td0 = 0; + td1 = 0; + } + + spi_writel(as, TDR, (td1 << 16) | td0); + num_data -= 2; + } + + if (num_data) { + if (xfer->tx_buf) { + if (xfer->bits_per_word > 8) + td0 = *words++; + else + td0 = *bytes++; + } else { + td0 = 0; + } + + spi_writew(as, TDR, td0); + num_data--; + } + + dev_dbg(master->dev.parent, + " start fifo xfer %p: len %u tx %p rx %p bitpw %d\n", + xfer, xfer->len, xfer->tx_buf, xfer->rx_buf, + xfer->bits_per_word); + + /* + * Enable RX FIFO Threshold Flag interrupt to be notified about + * transfer completion. + */ + spi_writel(as, IER, SPI_BIT(RXFTHF) | SPI_BIT(OVRES)); +} + +/* + * Next transfer using PIO. + */ +static void atmel_spi_next_xfer_pio(struct spi_master *master, + struct spi_transfer *xfer) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + + if (as->fifo_size) + atmel_spi_next_xfer_fifo(master, xfer); + else + atmel_spi_next_xfer_single(master, xfer); +} + +/* * Submit next transfer for DMA. - * lock is held, spi tasklet is blocked */ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, struct spi_transfer *xfer, @@ -599,28 +778,22 @@ goto err_exit; /* Send both scatterlists */ - rxdesc = rxchan->device->device_prep_slave_sg(rxchan, - &as->dma.sgrx, - 1, - DMA_FROM_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK, - NULL); + rxdesc = dmaengine_prep_slave_sg(rxchan, &as->dma.sgrx, 1, + DMA_FROM_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!rxdesc) goto err_dma; - txdesc = txchan->device->device_prep_slave_sg(txchan, - &as->dma.sgtx, - 1, - DMA_TO_DEVICE, - DMA_PREP_INTERRUPT | DMA_CTRL_ACK, - NULL); + txdesc = dmaengine_prep_slave_sg(txchan, &as->dma.sgtx, 1, + DMA_TO_DEVICE, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) goto err_dma; dev_dbg(master->dev.parent, - " start dma xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); + " start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma, + xfer->rx_buf, (unsigned long long)xfer->rx_dma); /* Enable relevant interrupts */ spi_writel(as, IER, SPI_BIT(OVRES)); @@ -683,73 +856,83 @@ *plen = len; } +static int atmel_spi_set_xfer_speed(struct atmel_spi *as, + struct spi_device *spi, + struct spi_transfer *xfer) +{ + u32 scbr, csr; + unsigned long bus_hz; + + /* v1 chips start out at half the peripheral bus speed. */ + bus_hz = clk_get_rate(as->clk); + if (!atmel_spi_is_v2(as)) + bus_hz /= 2; + + /* + * Calculate the lowest divider that satisfies the + * constraint, assuming div32/fdiv/mbz == 0. + */ + scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz); + + /* + * If the resulting divider doesn't fit into the + * register bitfield, we can't satisfy the constraint. + */ + if (scbr >= (1 << SPI_SCBR_SIZE)) { + dev_err(&spi->dev, + "setup: %d Hz too slow, scbr %u; min %ld Hz\n", + xfer->speed_hz, scbr, bus_hz/255); + return -EINVAL; + } + if (scbr == 0) { + dev_err(&spi->dev, + "setup: %d Hz too high, scbr %u; max %ld Hz\n", + xfer->speed_hz, scbr, bus_hz); + return -EINVAL; + } + csr = spi_readl(as, CSR0 + 4 * spi->chip_select); + csr = SPI_BFINS(SCBR, scbr, csr); + spi_writel(as, CSR0 + 4 * spi->chip_select, csr); + + return 0; +} + /* * Submit next transfer for PDC. * lock is held, spi irq is blocked */ static void atmel_spi_pdc_next_xfer(struct spi_master *master, - struct spi_message *msg) + struct spi_message *msg, + struct spi_transfer *xfer) { struct atmel_spi *as = spi_master_get_devdata(master); - struct spi_transfer *xfer; - u32 len, remaining; - u32 ieval; + u32 len; dma_addr_t tx_dma, rx_dma; - if (!as->current_transfer) - xfer = list_entry(msg->transfers.next, - struct spi_transfer, transfer_list); - else if (!as->next_transfer) - xfer = list_entry(as->current_transfer->transfer_list.next, - struct spi_transfer, transfer_list); - else - xfer = NULL; - - if (xfer) { - spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); - - len = xfer->len; - atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); - remaining = xfer->len - len; - - spi_writel(as, RPR, rx_dma); - spi_writel(as, TPR, tx_dma); - - if (msg->spi->bits_per_word > 8) - len >>= 1; - spi_writel(as, RCR, len); - spi_writel(as, TCR, len); - - dev_dbg(&msg->spi->dev, - " start xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); - } else { - xfer = as->next_transfer; - remaining = as->next_remaining_bytes; - } - - as->current_transfer = xfer; - as->current_remaining_bytes = remaining; - - if (remaining > 0) - len = remaining; - else if (!atmel_spi_xfer_is_last(msg, xfer) - && atmel_spi_xfer_can_be_chained(xfer)) { - xfer = list_entry(xfer->transfer_list.next, - struct spi_transfer, transfer_list); - len = xfer->len; - } else - xfer = NULL; - - as->next_transfer = xfer; + spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); - if (xfer) { - u32 total; + len = as->current_remaining_bytes; + atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); + as->current_remaining_bytes -= len; + + spi_writel(as, RPR, rx_dma); + spi_writel(as, TPR, tx_dma); + + if (msg->spi->bits_per_word > 8) + len >>= 1; + spi_writel(as, RCR, len); + spi_writel(as, TCR, len); + + dev_dbg(&msg->spi->dev, + " start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, + (unsigned long long)xfer->tx_dma, xfer->rx_buf, + (unsigned long long)xfer->rx_dma); - total = len; + if (as->current_remaining_bytes) { + len = as->current_remaining_bytes; atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); - as->next_remaining_bytes = total - len; + as->current_remaining_bytes -= len; spi_writel(as, RNPR, rx_dma); spi_writel(as, TNPR, tx_dma); @@ -760,103 +943,27 @@ spi_writel(as, TNCR, len); dev_dbg(&msg->spi->dev, - " next xfer %p: len %u tx %p/%08x rx %p/%08x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma); - ieval = SPI_BIT(ENDRX) | SPI_BIT(OVRES); - } else { - spi_writel(as, RNCR, 0); - spi_writel(as, TNCR, 0); - ieval = SPI_BIT(RXBUFF) | SPI_BIT(ENDRX) | SPI_BIT(OVRES); + " next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", + xfer, xfer->len, xfer->tx_buf, + (unsigned long long)xfer->tx_dma, xfer->rx_buf, + (unsigned long long)xfer->rx_dma); } - /* REVISIT: We're waiting for ENDRX before we start the next + /* REVISIT: We're waiting for RXBUFF before we start the next * transfer because we need to handle some difficult timing - * issues otherwise. If we wait for ENDTX in one transfer and - * then starts waiting for ENDRX in the next, it's difficult - * to tell the difference between the ENDRX interrupt we're - * actually waiting for and the ENDRX interrupt of the + * issues otherwise. If we wait for TXBUFE in one transfer and + * then starts waiting for RXBUFF in the next, it's difficult + * to tell the difference between the RXBUFF interrupt we're + * actually waiting for and the RXBUFF interrupt of the * previous transfer. * * It should be doable, though. Just not now... */ - spi_writel(as, IER, ieval); + spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES)); spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); } /* - * Choose way to submit next transfer and start it. - * lock is held, spi tasklet is blocked - */ -static void atmel_spi_dma_next_xfer(struct spi_master *master, - struct spi_message *msg) -{ - struct atmel_spi *as = spi_master_get_devdata(master); - struct spi_transfer *xfer; - u32 remaining, len; - - remaining = as->current_remaining_bytes; - if (remaining) { - xfer = as->current_transfer; - len = remaining; - } else { - if (!as->current_transfer) - xfer = list_entry(msg->transfers.next, - struct spi_transfer, transfer_list); - else - xfer = list_entry( - as->current_transfer->transfer_list.next, - struct spi_transfer, transfer_list); - - as->current_transfer = xfer; - len = xfer->len; - } - - if (atmel_spi_use_dma(as, xfer)) { - u32 total = len; - if (!atmel_spi_next_xfer_dma_submit(master, xfer, &len)) { - as->current_remaining_bytes = total - len; - return; - } else { - dev_err(&msg->spi->dev, "unable to use DMA, fallback to PIO\n"); - } - } - - /* use PIO if error appened using DMA */ - atmel_spi_next_xfer_pio(master, xfer); -} - -static void atmel_spi_next_message(struct spi_master *master) -{ - struct atmel_spi *as = spi_master_get_devdata(master); - struct spi_message *msg; - struct spi_device *spi; - - BUG_ON(as->current_transfer); - - msg = list_entry(as->queue.next, struct spi_message, queue); - spi = msg->spi; - - dev_dbg(master->dev.parent, "start message %p for %s\n", - msg, dev_name(&spi->dev)); - - /* select chip if it's not still active */ - if (as->stay) { - if (as->stay != spi) { - cs_deactivate(as, as->stay); - cs_activate(as, spi); - } - as->stay = NULL; - } else - cs_activate(as, spi); - - if (as->use_pdc) - atmel_spi_pdc_next_xfer(master, msg); - else - atmel_spi_dma_next_xfer(master, msg); -} - -/* * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma: * - The buffer is either valid for CPU access, else NULL * - If the buffer is valid, so is its DMA address @@ -912,50 +1019,9 @@ } static void -atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, - struct spi_message *msg, int stay) -{ - if (!stay || as->done_status < 0) - cs_deactivate(as, msg->spi); - else - as->stay = msg->spi; - - list_del(&msg->queue); - msg->status = as->done_status; - - dev_dbg(master->dev.parent, - "xfer complete: %u bytes transferred\n", - msg->actual_length); - - atmel_spi_unlock(as); - msg->complete(msg->context); - atmel_spi_lock(as); - - as->current_transfer = NULL; - as->next_transfer = NULL; - as->done_status = 0; - - /* continue if needed */ - if (list_empty(&as->queue) || as->stopping) { - if (as->use_pdc) - atmel_spi_disable_pdc_transfer(as); - } else { - atmel_spi_next_message(master); - } -} - -/* Called from IRQ - * lock is held - * - * Must update "current_remaining_bytes" to keep track of data - * to transfer. - */ -static void -atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) +atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer) { - u8 *txp; u8 *rxp; - u16 *txp16; u16 *rxp16; unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; @@ -971,102 +1037,70 @@ spi_readl(as, RDR); } if (xfer->bits_per_word > 8) { - as->current_remaining_bytes -= 2; - if (as->current_remaining_bytes < 0) + if (as->current_remaining_bytes > 2) + as->current_remaining_bytes -= 2; + else as->current_remaining_bytes = 0; } else { as->current_remaining_bytes--; } - - if (as->current_remaining_bytes) { - if (xfer->tx_buf) { - if (xfer->bits_per_word > 8) { - txp16 = (u16 *)(((u8 *)xfer->tx_buf) - + xfer_pos + 2); - spi_writel(as, TDR, *txp16); - } else { - txp = ((u8 *)xfer->tx_buf) + xfer_pos + 1; - spi_writel(as, TDR, *txp); - } - } else { - spi_writel(as, TDR, 0); - } - } } -/* Tasklet - * Called from DMA callback + pio transfer and overrun IRQ. - */ -static void atmel_spi_tasklet_func(unsigned long data) +static void +atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer) { - struct spi_master *master = (struct spi_master *)data; - struct atmel_spi *as = spi_master_get_devdata(master); - struct spi_message *msg; - struct spi_transfer *xfer; + u32 fifolr = spi_readl(as, FLR); + u32 num_bytes, num_data = SPI_BFEXT(RXFL, fifolr); + u32 offset = xfer->len - as->current_remaining_bytes; + u16 *words = (u16 *)((u8 *)xfer->rx_buf + offset); + u8 *bytes = (u8 *)((u8 *)xfer->rx_buf + offset); + u16 rd; /* RD field is the lowest 16 bits of RDR */ + + /* Update the number of remaining bytes to transfer */ + num_bytes = ((xfer->bits_per_word > 8) ? + (num_data << 1) : + num_data); - dev_vdbg(master->dev.parent, "atmel_spi_tasklet_func\n"); - - atmel_spi_lock(as); - - xfer = as->current_transfer; - - if (xfer == NULL) - /* already been there */ - goto tasklet_out; - - msg = list_entry(as->queue.next, struct spi_message, queue); - - if (as->current_remaining_bytes == 0) { - if (as->done_status < 0) { - /* error happened (overrun) */ - if (atmel_spi_use_dma(as, xfer)) - atmel_spi_stop_dma(as); - } else { - /* only update length if no error */ - msg->actual_length += xfer->len; - } - - if (atmel_spi_use_dma(as, xfer)) - if (!msg->is_dma_mapped) - atmel_spi_dma_unmap_xfer(master, xfer); - - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); - - if (atmel_spi_xfer_is_last(msg, xfer) || as->done_status < 0) { - /* report completed (or erroneous) message */ - atmel_spi_msg_done(master, as, msg, xfer->cs_change); - } else { - if (xfer->cs_change) { - cs_deactivate(as, msg->spi); - udelay(1); - cs_activate(as, msg->spi); - } + if (as->current_remaining_bytes > num_bytes) + as->current_remaining_bytes -= num_bytes; + else + as->current_remaining_bytes = 0; - /* - * Not done yet. Submit the next transfer. - * - * FIXME handle protocol options for xfer - */ - atmel_spi_dma_next_xfer(master, msg); + /* Handle odd number of bytes when data are more than 8bit width */ + if (xfer->bits_per_word > 8) + as->current_remaining_bytes &= ~0x1; + + /* Read data */ + while (num_data) { + rd = spi_readl(as, RDR); + if (xfer->rx_buf) { + if (xfer->bits_per_word > 8) + *words++ = rd; + else + *bytes++ = rd; } - } else { - /* - * Keep going, we still have data to send in - * the current transfer. - */ - atmel_spi_dma_next_xfer(master, msg); + num_data--; } +} -tasklet_out: - atmel_spi_unlock(as); +/* Called from IRQ + * + * Must update "current_remaining_bytes" to keep track of data + * to transfer. + */ +static void +atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) +{ + if (as->fifo_size) + atmel_spi_pump_fifo_data(as, xfer); + else + atmel_spi_pump_single_data(as, xfer); } /* Interrupt * * No need for locking in this Interrupt handler: done_status is the - * only information modified. What we need is the update of this field - * before tasklet runs. This is ensured by using barrier. + * only information modified. */ static irqreturn_t atmel_spi_pio_interrupt(int irq, void *dev_id) @@ -1094,8 +1128,6 @@ * * We will also not process any remaning transfers in * the message. - * - * All actions are done in tasklet with done_status indication */ as->done_status = -EIO; smp_wmb(); @@ -1103,20 +1135,19 @@ /* Clear any overrun happening while cleaning up */ spi_readl(as, SR); - tasklet_schedule(&as->tasklet); + complete(&as->xfer_completion); - } else if (pending & SPI_BIT(RDRF)) { + } else if (pending & (SPI_BIT(RDRF) | SPI_BIT(RXFTHF))) { atmel_spi_lock(as); if (as->current_remaining_bytes) { ret = IRQ_HANDLED; xfer = as->current_transfer; atmel_spi_pump_pio_data(as, xfer); - if (!as->current_remaining_bytes) { - /* no more data to xfer, kick tasklet */ + if (!as->current_remaining_bytes) spi_writel(as, IDR, pending); - tasklet_schedule(&as->tasklet); - } + + complete(&as->xfer_completion); } atmel_spi_unlock(as); @@ -1134,116 +1165,35 @@ { struct spi_master *master = dev_id; struct atmel_spi *as = spi_master_get_devdata(master); - struct spi_message *msg; - struct spi_transfer *xfer; u32 status, pending, imr; int ret = IRQ_NONE; - atmel_spi_lock(as); - - xfer = as->current_transfer; - msg = list_entry(as->queue.next, struct spi_message, queue); - imr = spi_readl(as, IMR); status = spi_readl(as, SR); pending = status & imr; if (pending & SPI_BIT(OVRES)) { - int timeout; ret = IRQ_HANDLED; spi_writel(as, IDR, (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX) | SPI_BIT(OVRES))); - /* - * When we get an overrun, we disregard the current - * transfer. Data will not be copied back from any - * bounce buffer and msg->actual_len will not be - * updated with the last xfer. - * - * We will also not process any remaning transfers in - * the message. - * - * First, stop the transfer and unmap the DMA buffers. - */ - spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); - if (!msg->is_dma_mapped) - atmel_spi_dma_unmap_xfer(master, xfer); - - /* REVISIT: udelay in irq is unfriendly */ - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); - - dev_warn(master->dev.parent, "overrun (%u/%u remaining)\n", - spi_readl(as, TCR), spi_readl(as, RCR)); - - /* - * Clean up DMA registers and make sure the data - * registers are empty. - */ - spi_writel(as, RNCR, 0); - spi_writel(as, TNCR, 0); - spi_writel(as, RCR, 0); - spi_writel(as, TCR, 0); - for (timeout = 1000; timeout; timeout--) - if (spi_readl(as, SR) & SPI_BIT(TXEMPTY)) - break; - if (!timeout) - dev_warn(master->dev.parent, - "timeout waiting for TXEMPTY"); - while (spi_readl(as, SR) & SPI_BIT(RDRF)) - spi_readl(as, RDR); - /* Clear any overrun happening while cleaning up */ spi_readl(as, SR); as->done_status = -EIO; - atmel_spi_msg_done(master, as, msg, 0); + + complete(&as->xfer_completion); + } else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) { ret = IRQ_HANDLED; spi_writel(as, IDR, pending); - if (as->current_remaining_bytes == 0) { - msg->actual_length += xfer->len; - - if (!msg->is_dma_mapped) - atmel_spi_dma_unmap_xfer(master, xfer); - - /* REVISIT: udelay in irq is unfriendly */ - if (xfer->delay_usecs) - udelay(xfer->delay_usecs); - - if (atmel_spi_xfer_is_last(msg, xfer)) { - /* report completed message */ - atmel_spi_msg_done(master, as, msg, - xfer->cs_change); - } else { - if (xfer->cs_change) { - cs_deactivate(as, msg->spi); - udelay(1); - cs_activate(as, msg->spi); - } - - /* - * Not done yet. Submit the next transfer. - * - * FIXME handle protocol options for xfer - */ - atmel_spi_pdc_next_xfer(master, msg); - } - } else { - /* - * Keep going, we still have data to send in - * the current transfer. - */ - atmel_spi_pdc_next_xfer(master, msg); - } + complete(&as->xfer_completion); } - atmel_spi_unlock(as); - return ret; } @@ -1251,31 +1201,13 @@ { struct atmel_spi *as; struct atmel_spi_device *asd; - u32 scbr, csr; + u32 csr; unsigned int bits = spi->bits_per_word; - unsigned long bus_hz; unsigned int npcs_pin; int ret; as = spi_master_get_devdata(spi->master); - if (as->stopping) - return -ESHUTDOWN; - - 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; - } - - if (bits < 8 || bits > 16) { - dev_dbg(&spi->dev, - "setup: invalid bits_per_word %u (8 to 16)\n", - bits); - return -EINVAL; - } - /* see notes above re chipselect */ if (!atmel_spi_is_v2(as) && spi->chip_select == 0 @@ -1284,37 +1216,13 @@ return -EINVAL; } - /* v1 chips start out at half the peripheral bus speed. */ - bus_hz = clk_get_rate(as->clk); - if (!atmel_spi_is_v2(as)) - bus_hz /= 2; - - if (spi->max_speed_hz) { - /* - * Calculate the lowest divider that satisfies the - * constraint, assuming div32/fdiv/mbz == 0. - */ - scbr = DIV_ROUND_UP(bus_hz, spi->max_speed_hz); - - /* - * If the resulting divider doesn't fit into the - * register bitfield, we can't satisfy the constraint. - */ - if (scbr >= (1 << SPI_SCBR_SIZE)) { - dev_dbg(&spi->dev, - "setup: %d Hz too slow, scbr %u; min %ld Hz\n", - spi->max_speed_hz, scbr, bus_hz/255); - return -EINVAL; - } - } else - /* speed zero means "as slow as possible" */ - scbr = 0xff; - - csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8); + csr = SPI_BF(BITS, bits - 8); if (spi->mode & SPI_CPOL) csr |= SPI_BIT(CPOL); if (!(spi->mode & SPI_CPHA)) csr |= SPI_BIT(NCPHA); + if (!as->use_cs_gpios) + csr |= SPI_BIT(CSAAT); /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. * @@ -1326,9 +1234,11 @@ csr |= SPI_BF(DLYBCT, 0); /* chipselect must have been muxed as GPIO (e.g. in board setup) */ - npcs_pin = (unsigned int)spi->controller_data; + npcs_pin = (unsigned long)spi->controller_data; - if (gpio_is_valid(spi->cs_gpio)) + if (!as->use_cs_gpios) + npcs_pin = spi->chip_select; + else if (gpio_is_valid(spi->cs_gpio)) npcs_pin = spi->cs_gpio; asd = spi->controller_state; @@ -1337,28 +1247,26 @@ if (!asd) return -ENOMEM; - ret = gpio_request(npcs_pin, dev_name(&spi->dev)); - if (ret) { - kfree(asd); - return ret; + if (as->use_cs_gpios) { + ret = gpio_request(npcs_pin, dev_name(&spi->dev)); + if (ret) { + kfree(asd); + return ret; + } + + gpio_direction_output(npcs_pin, + !(spi->mode & SPI_CS_HIGH)); } asd->npcs_pin = npcs_pin; spi->controller_state = asd; - gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); - } else { - atmel_spi_lock(as); - if (as->stay == spi) - as->stay = NULL; - cs_deactivate(as, spi); - atmel_spi_unlock(as); } asd->csr = csr; dev_dbg(&spi->dev, - "setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n", - bus_hz / scbr, bits, spi->mode, spi->chip_select, csr); + "setup: bpw %u mode 0x%x -> csr%d %08x\n", + bits, spi->mode, spi->chip_select, csr); if (!atmel_spi_is_v2(as)) spi_writel(as, CSR0 + 4 * spi->chip_select, csr); @@ -1366,103 +1274,208 @@ return 0; } -static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg) +static int atmel_spi_one_transfer(struct spi_master *master, + struct spi_message *msg, + struct spi_transfer *xfer) { struct atmel_spi *as; - struct spi_transfer *xfer; - struct device *controller = spi->master->dev.parent; + struct spi_device *spi = msg->spi; u8 bits; + u32 len; struct atmel_spi_device *asd; + int timeout; + int ret; + unsigned long dma_timeout; - as = spi_master_get_devdata(spi->master); - - dev_dbg(controller, "new message %p submitted for %s\n", - msg, dev_name(&spi->dev)); + as = spi_master_get_devdata(master); - if (unlikely(list_empty(&msg->transfers))) + if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) { + dev_dbg(&spi->dev, "missing rx or tx buf\n"); return -EINVAL; + } - if (as->stopping) - return -ESHUTDOWN; + asd = spi->controller_state; + bits = (asd->csr >> 4) & 0xf; + if (bits != xfer->bits_per_word - 8) { + dev_dbg(&spi->dev, + "you can't yet change bits_per_word in transfers\n"); + return -ENOPROTOOPT; + } - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (!(xfer->tx_buf || xfer->rx_buf) && xfer->len) { - dev_dbg(&spi->dev, "missing rx or tx buf\n"); - return -EINVAL; - } + /* + * DMA map early, for performance (empties dcache ASAP) and + * better fault reporting. + */ + if ((!msg->is_dma_mapped) + && (atmel_spi_use_dma(as, xfer) || as->use_pdc)) { + if (atmel_spi_dma_map_xfer(as, xfer) < 0) + return -ENOMEM; + } + + atmel_spi_set_xfer_speed(as, msg->spi, xfer); - if (xfer->bits_per_word) { - asd = spi->controller_state; - bits = (asd->csr >> 4) & 0xf; - if (bits != xfer->bits_per_word - 8) { - dev_dbg(&spi->dev, "you can't yet change " - "bits_per_word in transfers\n"); - return -ENOPROTOOPT; + as->done_status = 0; + as->current_transfer = xfer; + as->current_remaining_bytes = xfer->len; + while (as->current_remaining_bytes) { + reinit_completion(&as->xfer_completion); + + if (as->use_pdc) { + atmel_spi_pdc_next_xfer(master, msg, xfer); + } else if (atmel_spi_use_dma(as, xfer)) { + len = as->current_remaining_bytes; + ret = atmel_spi_next_xfer_dma_submit(master, + xfer, &len); + if (ret) { + dev_err(&spi->dev, + "unable to use DMA, fallback to PIO\n"); + atmel_spi_next_xfer_pio(master, xfer); + } else { + as->current_remaining_bytes -= len; + if (as->current_remaining_bytes < 0) + as->current_remaining_bytes = 0; } + } else { + atmel_spi_next_xfer_pio(master, xfer); } - if (xfer->bits_per_word > 8) { - if (xfer->len % 2) { - dev_dbg(&spi->dev, "buffer len should be 16 bits aligned\n"); - return -EINVAL; - } + /* interrupts are disabled, so free the lock for schedule */ + atmel_spi_unlock(as); + dma_timeout = wait_for_completion_timeout(&as->xfer_completion, + SPI_DMA_TIMEOUT); + atmel_spi_lock(as); + if (WARN_ON(dma_timeout == 0)) { + dev_err(&spi->dev, "spi transfer timeout\n"); + as->done_status = -EIO; } - /* FIXME implement these protocol options!! */ - if (xfer->speed_hz < spi->max_speed_hz) { - dev_dbg(&spi->dev, "can't change speed in transfer\n"); - return -ENOPROTOOPT; + if (as->done_status) + break; + } + + if (as->done_status) { + if (as->use_pdc) { + dev_warn(master->dev.parent, + "overrun (%u/%u remaining)\n", + spi_readl(as, TCR), spi_readl(as, RCR)); + + /* + * Clean up DMA registers and make sure the data + * registers are empty. + */ + spi_writel(as, RNCR, 0); + spi_writel(as, TNCR, 0); + spi_writel(as, RCR, 0); + spi_writel(as, TCR, 0); + for (timeout = 1000; timeout; timeout--) + if (spi_readl(as, SR) & SPI_BIT(TXEMPTY)) + break; + if (!timeout) + dev_warn(master->dev.parent, + "timeout waiting for TXEMPTY"); + while (spi_readl(as, SR) & SPI_BIT(RDRF)) + spi_readl(as, RDR); + + /* Clear any overrun happening while cleaning up */ + spi_readl(as, SR); + + } else if (atmel_spi_use_dma(as, xfer)) { + atmel_spi_stop_dma(as); } - /* - * DMA map early, for performance (empties dcache ASAP) and - * better fault reporting. - */ - if ((!msg->is_dma_mapped) && (atmel_spi_use_dma(as, xfer) - || as->use_pdc)) { - if (atmel_spi_dma_map_xfer(as, xfer) < 0) - return -ENOMEM; + if (!msg->is_dma_mapped + && (atmel_spi_use_dma(as, xfer) || as->use_pdc)) + atmel_spi_dma_unmap_xfer(master, xfer); + + return 0; + + } else { + /* only update length if no error */ + msg->actual_length += xfer->len; + } + + if (!msg->is_dma_mapped + && (atmel_spi_use_dma(as, xfer) || as->use_pdc)) + atmel_spi_dma_unmap_xfer(master, xfer); + + if (xfer->delay_usecs) + udelay(xfer->delay_usecs); + + if (xfer->cs_change) { + if (list_is_last(&xfer->transfer_list, + &msg->transfers)) { + as->keep_cs = true; + } else { + as->cs_active = !as->cs_active; + if (as->cs_active) + cs_activate(as, msg->spi); + else + cs_deactivate(as, msg->spi); } } -#ifdef VERBOSE + return 0; +} + +static int atmel_spi_transfer_one_message(struct spi_master *master, + struct spi_message *msg) +{ + struct atmel_spi *as; + struct spi_transfer *xfer; + struct spi_device *spi = msg->spi; + int ret = 0; + + as = spi_master_get_devdata(master); + + dev_dbg(&spi->dev, "new message %p submitted for %s\n", + msg, dev_name(&spi->dev)); + + atmel_spi_lock(as); + cs_activate(as, spi); + + as->cs_active = true; + as->keep_cs = false; + + msg->status = 0; + msg->actual_length = 0; + + list_for_each_entry(xfer, &msg->transfers, transfer_list) { + ret = atmel_spi_one_transfer(master, msg, xfer); + if (ret) + goto msg_done; + } + + if (as->use_pdc) + atmel_spi_disable_pdc_transfer(as); + list_for_each_entry(xfer, &msg->transfers, transfer_list) { - dev_dbg(controller, - " xfer %p: len %u tx %p/%08x rx %p/%08x\n", + dev_dbg(&spi->dev, + " 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); } -#endif - msg->status = -EINPROGRESS; - msg->actual_length = 0; +msg_done: + if (!as->keep_cs) + cs_deactivate(as, msg->spi); - atmel_spi_lock(as); - list_add_tail(&msg->queue, &as->queue); - if (!as->current_transfer) - atmel_spi_next_message(spi->master); atmel_spi_unlock(as); - return 0; + msg->status = as->done_status; + spi_finalize_current_message(spi->master); + + return ret; } static void atmel_spi_cleanup(struct spi_device *spi) { - struct atmel_spi *as = spi_master_get_devdata(spi->master); struct atmel_spi_device *asd = spi->controller_state; - unsigned gpio = (unsigned) spi->controller_data; + unsigned gpio = (unsigned long) spi->controller_data; if (!asd) return; - atmel_spi_lock(as); - if (as->stay == spi) { - as->stay = NULL; - cs_deactivate(as, spi); - } - atmel_spi_unlock(as); - spi->controller_state = NULL; gpio_free(gpio); kfree(asd); @@ -1496,6 +1509,9 @@ 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; @@ -1504,25 +1520,26 @@ if (irq < 0) return irq; - clk = clk_get(&pdev->dev, "spi_clk"); + clk = devm_clk_get(&pdev->dev, "spi_clk"); if (IS_ERR(clk)) return PTR_ERR(clk); /* setup spi core then atmel-specific driver state */ ret = -ENOMEM; - master = spi_alloc_master(&pdev->dev, sizeof *as); + master = spi_alloc_master(&pdev->dev, sizeof(*as)); if (!master) goto out_free; /* 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(8, 16); master->dev.of_node = pdev->dev.of_node; master->bus_num = pdev->id; master->num_chipselect = master->dev.of_node ? 0 : 4; master->setup = atmel_spi_setup; - master->transfer = atmel_spi_transfer; + master->transfer_one_message = atmel_spi_transfer_one_message; master->cleanup = atmel_spi_cleanup; + master->auto_runtime_pm = true; platform_set_drvdata(pdev, master); as = spi_master_get_devdata(master); @@ -1537,23 +1554,37 @@ goto out_free; spin_lock_init(&as->lock); - INIT_LIST_HEAD(&as->queue); as->pdev = pdev; - as->regs = ioremap(regs->start, resource_size(regs)); - if (!as->regs) + as->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(as->regs)) { + ret = PTR_ERR(as->regs); goto out_free_buffer; + } as->phybase = regs->start; as->irq = irq; as->clk = clk; + init_completion(&as->xfer_completion); + atmel_get_caps(as); + as->use_cs_gpios = true; + if (atmel_spi_is_v2(as) && + pdev->dev.of_node && + !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) { + as->use_cs_gpios = false; + master->num_chipselect = 4; + } + as->use_dma = false; as->use_pdc = false; if (as->caps.has_dma_support) { - if (atmel_spi_configure_dma(as) == 0) + ret = atmel_spi_configure_dma(as); + if (ret == 0) as->use_dma = true; + else if (ret == -EPROBE_DEFER) + return ret; } else { as->use_pdc = true; } @@ -1562,20 +1593,19 @@ dev_info(&pdev->dev, "Atmel SPI Controller using PIO only\n"); if (as->use_pdc) { - ret = request_irq(irq, atmel_spi_pdc_interrupt, 0, - dev_name(&pdev->dev), master); + ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pdc_interrupt, + 0, dev_name(&pdev->dev), master); } else { - tasklet_init(&as->tasklet, atmel_spi_tasklet_func, - (unsigned long)master); - - ret = request_irq(irq, atmel_spi_pio_interrupt, 0, - dev_name(&pdev->dev), master); + ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pio_interrupt, + 0, dev_name(&pdev->dev), master); } if (ret) goto out_unmap_regs; /* Initialize the hardware */ - clk_enable(clk); + ret = clk_prepare_enable(clk); + if (ret) + goto out_free_irq; spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ if (as->caps.has_wdrbt) { @@ -1589,33 +1619,44 @@ spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); spi_writel(as, CR, SPI_BIT(SPIEN)); + as->fifo_size = 0; + if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", + &as->fifo_size)) { + dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size); + spi_writel(as, CR, SPI_BIT(FIFOEN)); + } + /* go! */ dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n", (unsigned long)regs->start, irq); - ret = spi_register_master(master); + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + ret = devm_spi_register_master(&pdev->dev, master); if (ret) goto out_free_dma; return 0; out_free_dma: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + if (as->use_dma) atmel_spi_release_dma(as); spi_writel(as, CR, SPI_BIT(SWRST)); spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ - clk_disable(clk); - free_irq(irq, master); + clk_disable_unprepare(clk); +out_free_irq: out_unmap_regs: - iounmap(as->regs); out_free_buffer: - if (!as->use_pdc) - tasklet_kill(&as->tasklet); dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, as->buffer_dma); out_free: - clk_put(clk); spi_master_put(master); return ret; } @@ -1624,12 +1665,11 @@ { struct spi_master *master = platform_get_drvdata(pdev); struct atmel_spi *as = spi_master_get_devdata(master); - struct spi_message *msg; - struct spi_transfer *xfer; + + pm_runtime_get_sync(&pdev->dev); /* reset the hardware and block queue progress */ spin_lock_irq(&as->lock); - as->stopping = 1; if (as->use_dma) { atmel_spi_stop_dma(as); atmel_spi_release_dma(as); @@ -1640,56 +1680,86 @@ spi_readl(as, SR); spin_unlock_irq(&as->lock); - /* Terminate remaining queued transfers */ - list_for_each_entry(msg, &as->queue, queue) { - list_for_each_entry(xfer, &msg->transfers, transfer_list) { - if (!msg->is_dma_mapped - && (atmel_spi_use_dma(as, xfer) - || as->use_pdc)) - atmel_spi_dma_unmap_xfer(master, xfer); - } - msg->status = -ESHUTDOWN; - msg->complete(msg->context); - } - - if (!as->use_pdc) - tasklet_kill(&as->tasklet); dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer, as->buffer_dma); - clk_disable(as->clk); - clk_put(as->clk); - free_irq(as->irq, master); - iounmap(as->regs); + clk_disable_unprepare(as->clk); - spi_unregister_master(master); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } -#ifdef CONFIG_PM - -static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg) +#ifdef CONFIG_PM +static int atmel_spi_runtime_suspend(struct device *dev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_master *master = dev_get_drvdata(dev); + struct atmel_spi *as = spi_master_get_devdata(master); + + clk_disable_unprepare(as->clk); + pinctrl_pm_select_sleep_state(dev); - clk_disable(as->clk); return 0; } -static int atmel_spi_resume(struct platform_device *pdev) +static int atmel_spi_runtime_resume(struct device *dev) { - struct spi_master *master = platform_get_drvdata(pdev); - struct atmel_spi *as = spi_master_get_devdata(master); + struct spi_master *master = dev_get_drvdata(dev); + struct atmel_spi *as = spi_master_get_devdata(master); + + pinctrl_pm_select_default_state(dev); + + return clk_prepare_enable(as->clk); +} + +#ifdef CONFIG_PM_SLEEP +static int atmel_spi_suspend(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + /* Stop the queue running */ + ret = spi_master_suspend(master); + if (ret) { + dev_warn(dev, "cannot suspend master\n"); + return ret; + } + + if (!pm_runtime_suspended(dev)) + atmel_spi_runtime_suspend(dev); - clk_enable(as->clk); return 0; } +static int atmel_spi_resume(struct device *dev) +{ + struct spi_master *master = dev_get_drvdata(dev); + int ret; + + if (!pm_runtime_suspended(dev)) { + ret = atmel_spi_runtime_resume(dev); + if (ret) + return ret; + } + + /* Start the queue running */ + ret = spi_master_resume(master); + if (ret) + dev_err(dev, "problem starting queue (%d)\n", ret); + + return ret; +} +#endif + +static const struct dev_pm_ops atmel_spi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume) + SET_RUNTIME_PM_OPS(atmel_spi_runtime_suspend, + atmel_spi_runtime_resume, NULL) +}; +#define ATMEL_SPI_PM_OPS (&atmel_spi_pm_ops) #else -#define atmel_spi_suspend NULL -#define atmel_spi_resume NULL +#define ATMEL_SPI_PM_OPS NULL #endif #if defined(CONFIG_OF) @@ -1704,11 +1774,9 @@ static struct platform_driver atmel_spi_driver = { .driver = { .name = "atmel_spi", - .owner = THIS_MODULE, + .pm = ATMEL_SPI_PM_OPS, .of_match_table = of_match_ptr(atmel_spi_dt_ids), }, - .suspend = atmel_spi_suspend, - .resume = atmel_spi_resume, .probe = atmel_spi_probe, .remove = atmel_spi_remove, };