Loading Documentation/devicetree/bindings/spi/omap-spi.txt +26 −1 Original line number Original line Diff line number Diff line Loading @@ -10,7 +10,18 @@ Required properties: input. The default is D0 as input and input. The default is D0 as input and D1 as output. D1 as output. Example: Optional properties: - dmas: List of DMA specifiers with the controller specific format as described in the generic DMA client binding. A tx and rx specifier is required for each chip select. - dma-names: List of DMA request names. These strings correspond 1:1 with the DMA specifiers listed in dmas. The string naming is to be "rxN" and "txN" for RX and TX requests, respectively, where N equals the chip select number. Examples: [hwmod populated DMA resources] mcspi1: mcspi@1 { mcspi1: mcspi@1 { #address-cells = <1>; #address-cells = <1>; Loading @@ -20,3 +31,17 @@ mcspi1: mcspi@1 { ti,spi-num-cs = <4>; ti,spi-num-cs = <4>; }; }; [generic DMA request binding] mcspi1: mcspi@1 { #address-cells = <1>; #size-cells = <0>; compatible = "ti,omap4-mcspi"; ti,hwmods = "mcspi1"; ti,spi-num-cs = <2>; dmas = <&edma 42 &edma 43 &edma 44 &edma 45>; dma-names = "tx0", "rx0", "tx1", "rx1"; }; drivers/spi/spi-omap2-mcspi.c +187 −50 Original line number Original line Diff line number Diff line Loading @@ -38,13 +38,15 @@ #include <linux/pm_runtime.h> #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/gcd.h> #include <linux/spi/spi.h> #include <linux/spi/spi.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include <linux/platform_data/spi-omap2-mcspi.h> #define OMAP2_MCSPI_MAX_FREQ 48000000 #define OMAP2_MCSPI_MAX_FREQ 48000000 #define OMAP2_MCSPI_MAX_FIFODEPTH 64 #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF #define SPI_AUTOSUSPEND_TIMEOUT 2000 #define SPI_AUTOSUSPEND_TIMEOUT 2000 #define OMAP2_MCSPI_REVISION 0x00 #define OMAP2_MCSPI_REVISION 0x00 Loading @@ -54,6 +56,7 @@ #define OMAP2_MCSPI_WAKEUPENABLE 0x20 #define OMAP2_MCSPI_WAKEUPENABLE 0x20 #define OMAP2_MCSPI_SYST 0x24 #define OMAP2_MCSPI_SYST 0x24 #define OMAP2_MCSPI_MODULCTRL 0x28 #define OMAP2_MCSPI_MODULCTRL 0x28 #define OMAP2_MCSPI_XFERLEVEL 0x7c /* per-channel banks, 0x14 bytes each, first is: */ /* per-channel banks, 0x14 bytes each, first is: */ #define OMAP2_MCSPI_CHCONF0 0x2c #define OMAP2_MCSPI_CHCONF0 0x2c Loading @@ -63,6 +66,7 @@ #define OMAP2_MCSPI_RX0 0x3c #define OMAP2_MCSPI_RX0 0x3c /* per-register bitmasks: */ /* per-register bitmasks: */ #define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17) #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) Loading @@ -83,10 +87,13 @@ #define OMAP2_MCSPI_CHCONF_IS BIT(18) #define OMAP2_MCSPI_CHCONF_IS BIT(18) #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) #define OMAP2_MCSPI_CHCONF_FFET BIT(27) #define OMAP2_MCSPI_CHCONF_FFER BIT(28) #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) #define OMAP2_MCSPI_CHCTRL_EN BIT(0) #define OMAP2_MCSPI_CHCTRL_EN BIT(0) Loading @@ -102,6 +109,9 @@ struct omap2_mcspi_dma { struct completion dma_tx_completion; struct completion dma_tx_completion; struct completion dma_rx_completion; struct completion dma_rx_completion; char dma_rx_ch_name[14]; char dma_tx_ch_name[14]; }; }; /* use PIO for small transfers, avoiding DMA setup/teardown overhead and /* use PIO for small transfers, avoiding DMA setup/teardown overhead and Loading Loading @@ -129,6 +139,7 @@ struct omap2_mcspi { struct omap2_mcspi_dma *dma_channels; struct omap2_mcspi_dma *dma_channels; struct device *dev; struct device *dev; struct omap2_mcspi_regs ctx; struct omap2_mcspi_regs ctx; int fifo_depth; unsigned int pin_dir:1; unsigned int pin_dir:1; }; }; Loading Loading @@ -187,6 +198,16 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val) mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); } } static inline int mcspi_bytes_per_word(int word_len) { if (word_len <= 8) return 1; else if (word_len <= 16) return 2; else /* word_len <= 32 */ return 4; } static void omap2_mcspi_set_dma_req(const struct spi_device *spi, static void omap2_mcspi_set_dma_req(const struct spi_device *spi, int is_read, int enable) int is_read, int enable) { { Loading Loading @@ -248,6 +269,58 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master) ctx->modulctrl = l; ctx->modulctrl = l; } } static void omap2_mcspi_set_fifo(const struct spi_device *spi, struct spi_transfer *t, int enable) { struct spi_master *master = spi->master; struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi *mcspi; unsigned int wcnt; int fifo_depth, bytes_per_word; u32 chconf, xferlevel; mcspi = spi_master_get_devdata(master); chconf = mcspi_cached_chconf0(spi); if (enable) { bytes_per_word = mcspi_bytes_per_word(cs->word_len); if (t->len % bytes_per_word != 0) goto disable_fifo; fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH); if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0) goto disable_fifo; wcnt = t->len / bytes_per_word; if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) goto disable_fifo; xferlevel = wcnt << 16; if (t->rx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFER; xferlevel |= (fifo_depth - 1) << 8; } else { chconf |= OMAP2_MCSPI_CHCONF_FFET; xferlevel |= fifo_depth - 1; } mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel); mcspi_write_chconf0(spi, chconf); mcspi->fifo_depth = fifo_depth; return; } disable_fifo: if (t->rx_buf != NULL) chconf &= ~OMAP2_MCSPI_CHCONF_FFER; else chconf &= ~OMAP2_MCSPI_CHCONF_FFET; mcspi_write_chconf0(spi, chconf); mcspi->fifo_depth = 0; } static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) { { struct spi_master *spi_cntrl = mcspi->master; struct spi_master *spi_cntrl = mcspi->master; Loading Loading @@ -364,7 +437,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, { { struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_dma *mcspi_dma; unsigned int count; unsigned int count, dma_count; u32 l; u32 l; int elements = 0; int elements = 0; int word_len, element_count; int word_len, element_count; Loading @@ -372,6 +445,11 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select]; count = xfer->len; count = xfer->len; dma_count = xfer->len; if (mcspi->fifo_depth == 0) dma_count -= es; word_len = cs->word_len; word_len = cs->word_len; l = mcspi_cached_chconf0(spi); l = mcspi_cached_chconf0(spi); Loading @@ -385,16 +463,15 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, if (mcspi_dma->dma_rx) { if (mcspi_dma->dma_rx) { struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx; struct scatterlist sg; struct scatterlist sg; size_t len = xfer->len - es; dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); if (l & OMAP2_MCSPI_CHCONF_TURBO) if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) len -= es; dma_count -= es; sg_init_table(&sg, 1); sg_init_table(&sg, 1); sg_dma_address(&sg) = xfer->rx_dma; sg_dma_address(&sg) = xfer->rx_dma; sg_dma_len(&sg) = len; sg_dma_len(&sg) = dma_count; tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | Loading @@ -414,6 +491,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, wait_for_completion(&mcspi_dma->dma_rx_completion); wait_for_completion(&mcspi_dma->dma_rx_completion); dma_unmap_single(mcspi->dev, xfer->rx_dma, count, dma_unmap_single(mcspi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE); DMA_FROM_DEVICE); if (mcspi->fifo_depth > 0) return count; omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0); elements = element_count - 1; elements = element_count - 1; Loading @@ -433,10 +514,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, else /* word_len <= 32 */ else /* word_len <= 32 */ ((u32 *)xfer->rx_buf)[elements++] = w; ((u32 *)xfer->rx_buf)[elements++] = w; } else { } else { int bytes_per_word = mcspi_bytes_per_word(word_len); dev_err(&spi->dev, "DMA RX penultimate word empty"); dev_err(&spi->dev, "DMA RX penultimate word empty"); count -= (word_len <= 8) ? 2 : count -= (bytes_per_word << 1); (word_len <= 16) ? 4 : /* word_len <= 32 */ 8; omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 1); return count; return count; } } Loading @@ -454,9 +534,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ((u32 *)xfer->rx_buf)[elements] = w; ((u32 *)xfer->rx_buf)[elements] = w; } else { } else { dev_err(&spi->dev, "DMA RX last word empty"); dev_err(&spi->dev, "DMA RX last word empty"); count -= (word_len <= 8) ? 1 : count -= mcspi_bytes_per_word(word_len); (word_len <= 16) ? 2 : /* word_len <= 32 */ 4; } } omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 1); return count; return count; Loading @@ -475,7 +553,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) struct dma_slave_config cfg; struct dma_slave_config cfg; enum dma_slave_buswidth width; enum dma_slave_buswidth width; unsigned es; unsigned es; u32 burst; void __iomem *chstat_reg; void __iomem *chstat_reg; void __iomem *irqstat_reg; int wait_res; mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select]; Loading @@ -493,19 +574,27 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) es = 4; es = 4; } } count = xfer->len; burst = 1; if (mcspi->fifo_depth > 0) { if (count > mcspi->fifo_depth) burst = mcspi->fifo_depth / es; else burst = count / es; } memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg)); cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.src_addr_width = width; cfg.src_addr_width = width; cfg.dst_addr_width = width; cfg.dst_addr_width = width; cfg.src_maxburst = 1; cfg.src_maxburst = burst; cfg.dst_maxburst = 1; cfg.dst_maxburst = burst; rx = xfer->rx_buf; rx = xfer->rx_buf; tx = xfer->tx_buf; tx = xfer->tx_buf; count = xfer->len; if (tx != NULL) if (tx != NULL) omap2_mcspi_tx_dma(spi, xfer, cfg); omap2_mcspi_tx_dma(spi, xfer, cfg); Loading @@ -513,18 +602,38 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); if (tx != NULL) { if (tx != NULL) { chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; wait_for_completion(&mcspi_dma->dma_tx_completion); wait_for_completion(&mcspi_dma->dma_tx_completion); dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len, dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); DMA_TO_DEVICE); if (mcspi->fifo_depth > 0) { irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; if (mcspi_wait_for_reg_bit(irqstat_reg, OMAP2_MCSPI_IRQSTATUS_EOW) < 0) dev_err(&spi->dev, "EOW timed out\n"); mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS, OMAP2_MCSPI_IRQSTATUS_EOW); } /* for TX_ONLY mode, be sure all words have shifted out */ /* for TX_ONLY mode, be sure all words have shifted out */ if (rx == NULL) { if (rx == NULL) { if (mcspi_wait_for_reg_bit(chstat_reg, chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; OMAP2_MCSPI_CHSTAT_TXS) < 0) if (mcspi->fifo_depth > 0) { wait_res = mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXFFE); if (wait_res < 0) dev_err(&spi->dev, "TXFFE timed out\n"); } else { wait_res = mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXS); if (wait_res < 0) dev_err(&spi->dev, "TXS timed out\n"); dev_err(&spi->dev, "TXS timed out\n"); else if (mcspi_wait_for_reg_bit(chstat_reg, } OMAP2_MCSPI_CHSTAT_EOT) < 0) if (wait_res >= 0 && (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_EOT) < 0)) dev_err(&spi->dev, "EOT timed out\n"); dev_err(&spi->dev, "EOT timed out\n"); } } } } Loading Loading @@ -830,12 +939,20 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) dma_cap_zero(mask); dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask); sig = mcspi_dma->dma_rx_sync_dev; sig = mcspi_dma->dma_rx_sync_dev; mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); mcspi_dma->dma_rx = dma_request_slave_channel_compat(mask, omap_dma_filter_fn, &sig, &master->dev, mcspi_dma->dma_rx_ch_name); if (!mcspi_dma->dma_rx) if (!mcspi_dma->dma_rx) goto no_dma; goto no_dma; sig = mcspi_dma->dma_tx_sync_dev; sig = mcspi_dma->dma_tx_sync_dev; mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); mcspi_dma->dma_tx = dma_request_slave_channel_compat(mask, omap_dma_filter_fn, &sig, &master->dev, mcspi_dma->dma_tx_ch_name); if (!mcspi_dma->dma_tx) { if (!mcspi_dma->dma_tx) { dma_release_channel(mcspi_dma->dma_rx); dma_release_channel(mcspi_dma->dma_rx); mcspi_dma->dma_rx = NULL; mcspi_dma->dma_rx = NULL; Loading Loading @@ -945,7 +1062,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) cs = spi->controller_state; cs = spi->controller_state; cd = spi->controller_data; cd = spi->controller_data; omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 0); list_for_each_entry(t, &m->transfers, transfer_list) { list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { status = -EINVAL; status = -EINVAL; Loading Loading @@ -993,6 +1110,12 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) if (t->len) { if (t->len) { unsigned count; unsigned count; if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)) omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_enable(spi, 1); /* RX_ONLY mode needs dummy data in TX reg */ /* RX_ONLY mode needs dummy data in TX reg */ if (t->tx_buf == NULL) if (t->tx_buf == NULL) __raw_writel(0, cs->base __raw_writel(0, cs->base Loading @@ -1019,6 +1142,11 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) omap2_mcspi_force_cs(spi, 0); omap2_mcspi_force_cs(spi, 0); cs_active = 0; cs_active = 0; } } omap2_mcspi_set_enable(spi, 0); if (mcspi->fifo_depth > 0) omap2_mcspi_set_fifo(spi, t, 0); } } /* Restore defaults if they were overriden */ /* Restore defaults if they were overriden */ if (par_override) { if (par_override) { Loading @@ -1039,8 +1167,10 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0); m->status = status; if (mcspi->fifo_depth > 0 && t) omap2_mcspi_set_fifo(spi, t, 0); m->status = status; } } static int omap2_mcspi_transfer_one_message(struct spi_master *master, static int omap2_mcspi_transfer_one_message(struct spi_master *master, Loading Loading @@ -1177,7 +1307,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev) static int bus_num = 1; static int bus_num = 1; struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; const struct of_device_id *match; struct pinctrl *pinctrl; master = spi_alloc_master(&pdev->dev, sizeof *mcspi); master = spi_alloc_master(&pdev->dev, sizeof *mcspi); if (master == NULL) { if (master == NULL) { Loading Loading @@ -1247,39 +1376,47 @@ static int omap2_mcspi_probe(struct platform_device *pdev) goto free_master; goto free_master; for (i = 0; i < master->num_chipselect; i++) { for (i = 0; i < master->num_chipselect; i++) { char dma_ch_name[14]; char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name; char *dma_tx_ch_name = mcspi->dma_channels[i].dma_tx_ch_name; struct resource *dma_res; struct resource *dma_res; sprintf(dma_ch_name, "rx%d", i); sprintf(dma_rx_ch_name, "rx%d", i); dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, if (!pdev->dev.of_node) { dma_ch_name); dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, dma_rx_ch_name); if (!dma_res) { if (!dma_res) { dev_dbg(&pdev->dev, "cannot get DMA RX channel\n"); dev_dbg(&pdev->dev, "cannot get DMA RX channel\n"); status = -ENODEV; status = -ENODEV; break; break; } } mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start; mcspi->dma_channels[i].dma_rx_sync_dev = sprintf(dma_ch_name, "tx%d", i); dma_res->start; dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, } dma_ch_name); sprintf(dma_tx_ch_name, "tx%d", i); if (!pdev->dev.of_node) { dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, dma_tx_ch_name); if (!dma_res) { if (!dma_res) { dev_dbg(&pdev->dev, "cannot get DMA TX channel\n"); dev_dbg(&pdev->dev, "cannot get DMA TX channel\n"); status = -ENODEV; status = -ENODEV; break; break; } } mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; } } } if (status < 0) if (status < 0) goto dma_chnl_free; goto dma_chnl_free; pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) dev_warn(&pdev->dev, "pins are not configured from the driver\n"); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev); Loading Loading
Documentation/devicetree/bindings/spi/omap-spi.txt +26 −1 Original line number Original line Diff line number Diff line Loading @@ -10,7 +10,18 @@ Required properties: input. The default is D0 as input and input. The default is D0 as input and D1 as output. D1 as output. Example: Optional properties: - dmas: List of DMA specifiers with the controller specific format as described in the generic DMA client binding. A tx and rx specifier is required for each chip select. - dma-names: List of DMA request names. These strings correspond 1:1 with the DMA specifiers listed in dmas. The string naming is to be "rxN" and "txN" for RX and TX requests, respectively, where N equals the chip select number. Examples: [hwmod populated DMA resources] mcspi1: mcspi@1 { mcspi1: mcspi@1 { #address-cells = <1>; #address-cells = <1>; Loading @@ -20,3 +31,17 @@ mcspi1: mcspi@1 { ti,spi-num-cs = <4>; ti,spi-num-cs = <4>; }; }; [generic DMA request binding] mcspi1: mcspi@1 { #address-cells = <1>; #size-cells = <0>; compatible = "ti,omap4-mcspi"; ti,hwmods = "mcspi1"; ti,spi-num-cs = <2>; dmas = <&edma 42 &edma 43 &edma 44 &edma 45>; dma-names = "tx0", "rx0", "tx1", "rx1"; };
drivers/spi/spi-omap2-mcspi.c +187 −50 Original line number Original line Diff line number Diff line Loading @@ -38,13 +38,15 @@ #include <linux/pm_runtime.h> #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/gcd.h> #include <linux/spi/spi.h> #include <linux/spi/spi.h> #include <linux/platform_data/spi-omap2-mcspi.h> #include <linux/platform_data/spi-omap2-mcspi.h> #define OMAP2_MCSPI_MAX_FREQ 48000000 #define OMAP2_MCSPI_MAX_FREQ 48000000 #define OMAP2_MCSPI_MAX_FIFODEPTH 64 #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF #define SPI_AUTOSUSPEND_TIMEOUT 2000 #define SPI_AUTOSUSPEND_TIMEOUT 2000 #define OMAP2_MCSPI_REVISION 0x00 #define OMAP2_MCSPI_REVISION 0x00 Loading @@ -54,6 +56,7 @@ #define OMAP2_MCSPI_WAKEUPENABLE 0x20 #define OMAP2_MCSPI_WAKEUPENABLE 0x20 #define OMAP2_MCSPI_SYST 0x24 #define OMAP2_MCSPI_SYST 0x24 #define OMAP2_MCSPI_MODULCTRL 0x28 #define OMAP2_MCSPI_MODULCTRL 0x28 #define OMAP2_MCSPI_XFERLEVEL 0x7c /* per-channel banks, 0x14 bytes each, first is: */ /* per-channel banks, 0x14 bytes each, first is: */ #define OMAP2_MCSPI_CHCONF0 0x2c #define OMAP2_MCSPI_CHCONF0 0x2c Loading @@ -63,6 +66,7 @@ #define OMAP2_MCSPI_RX0 0x3c #define OMAP2_MCSPI_RX0 0x3c /* per-register bitmasks: */ /* per-register bitmasks: */ #define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17) #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) Loading @@ -83,10 +87,13 @@ #define OMAP2_MCSPI_CHCONF_IS BIT(18) #define OMAP2_MCSPI_CHCONF_IS BIT(18) #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) #define OMAP2_MCSPI_CHCONF_FFET BIT(27) #define OMAP2_MCSPI_CHCONF_FFER BIT(28) #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) #define OMAP2_MCSPI_CHCTRL_EN BIT(0) #define OMAP2_MCSPI_CHCTRL_EN BIT(0) Loading @@ -102,6 +109,9 @@ struct omap2_mcspi_dma { struct completion dma_tx_completion; struct completion dma_tx_completion; struct completion dma_rx_completion; struct completion dma_rx_completion; char dma_rx_ch_name[14]; char dma_tx_ch_name[14]; }; }; /* use PIO for small transfers, avoiding DMA setup/teardown overhead and /* use PIO for small transfers, avoiding DMA setup/teardown overhead and Loading Loading @@ -129,6 +139,7 @@ struct omap2_mcspi { struct omap2_mcspi_dma *dma_channels; struct omap2_mcspi_dma *dma_channels; struct device *dev; struct device *dev; struct omap2_mcspi_regs ctx; struct omap2_mcspi_regs ctx; int fifo_depth; unsigned int pin_dir:1; unsigned int pin_dir:1; }; }; Loading Loading @@ -187,6 +198,16 @@ static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val) mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); } } static inline int mcspi_bytes_per_word(int word_len) { if (word_len <= 8) return 1; else if (word_len <= 16) return 2; else /* word_len <= 32 */ return 4; } static void omap2_mcspi_set_dma_req(const struct spi_device *spi, static void omap2_mcspi_set_dma_req(const struct spi_device *spi, int is_read, int enable) int is_read, int enable) { { Loading Loading @@ -248,6 +269,58 @@ static void omap2_mcspi_set_master_mode(struct spi_master *master) ctx->modulctrl = l; ctx->modulctrl = l; } } static void omap2_mcspi_set_fifo(const struct spi_device *spi, struct spi_transfer *t, int enable) { struct spi_master *master = spi->master; struct omap2_mcspi_cs *cs = spi->controller_state; struct omap2_mcspi *mcspi; unsigned int wcnt; int fifo_depth, bytes_per_word; u32 chconf, xferlevel; mcspi = spi_master_get_devdata(master); chconf = mcspi_cached_chconf0(spi); if (enable) { bytes_per_word = mcspi_bytes_per_word(cs->word_len); if (t->len % bytes_per_word != 0) goto disable_fifo; fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH); if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0) goto disable_fifo; wcnt = t->len / bytes_per_word; if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) goto disable_fifo; xferlevel = wcnt << 16; if (t->rx_buf != NULL) { chconf |= OMAP2_MCSPI_CHCONF_FFER; xferlevel |= (fifo_depth - 1) << 8; } else { chconf |= OMAP2_MCSPI_CHCONF_FFET; xferlevel |= fifo_depth - 1; } mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel); mcspi_write_chconf0(spi, chconf); mcspi->fifo_depth = fifo_depth; return; } disable_fifo: if (t->rx_buf != NULL) chconf &= ~OMAP2_MCSPI_CHCONF_FFER; else chconf &= ~OMAP2_MCSPI_CHCONF_FFET; mcspi_write_chconf0(spi, chconf); mcspi->fifo_depth = 0; } static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) { { struct spi_master *spi_cntrl = mcspi->master; struct spi_master *spi_cntrl = mcspi->master; Loading Loading @@ -364,7 +437,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, { { struct omap2_mcspi *mcspi; struct omap2_mcspi *mcspi; struct omap2_mcspi_dma *mcspi_dma; struct omap2_mcspi_dma *mcspi_dma; unsigned int count; unsigned int count, dma_count; u32 l; u32 l; int elements = 0; int elements = 0; int word_len, element_count; int word_len, element_count; Loading @@ -372,6 +445,11 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select]; count = xfer->len; count = xfer->len; dma_count = xfer->len; if (mcspi->fifo_depth == 0) dma_count -= es; word_len = cs->word_len; word_len = cs->word_len; l = mcspi_cached_chconf0(spi); l = mcspi_cached_chconf0(spi); Loading @@ -385,16 +463,15 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, if (mcspi_dma->dma_rx) { if (mcspi_dma->dma_rx) { struct dma_async_tx_descriptor *tx; struct dma_async_tx_descriptor *tx; struct scatterlist sg; struct scatterlist sg; size_t len = xfer->len - es; dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); if (l & OMAP2_MCSPI_CHCONF_TURBO) if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) len -= es; dma_count -= es; sg_init_table(&sg, 1); sg_init_table(&sg, 1); sg_dma_address(&sg) = xfer->rx_dma; sg_dma_address(&sg) = xfer->rx_dma; sg_dma_len(&sg) = len; sg_dma_len(&sg) = dma_count; tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | Loading @@ -414,6 +491,10 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, wait_for_completion(&mcspi_dma->dma_rx_completion); wait_for_completion(&mcspi_dma->dma_rx_completion); dma_unmap_single(mcspi->dev, xfer->rx_dma, count, dma_unmap_single(mcspi->dev, xfer->rx_dma, count, DMA_FROM_DEVICE); DMA_FROM_DEVICE); if (mcspi->fifo_depth > 0) return count; omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0); elements = element_count - 1; elements = element_count - 1; Loading @@ -433,10 +514,9 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, else /* word_len <= 32 */ else /* word_len <= 32 */ ((u32 *)xfer->rx_buf)[elements++] = w; ((u32 *)xfer->rx_buf)[elements++] = w; } else { } else { int bytes_per_word = mcspi_bytes_per_word(word_len); dev_err(&spi->dev, "DMA RX penultimate word empty"); dev_err(&spi->dev, "DMA RX penultimate word empty"); count -= (word_len <= 8) ? 2 : count -= (bytes_per_word << 1); (word_len <= 16) ? 4 : /* word_len <= 32 */ 8; omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 1); return count; return count; } } Loading @@ -454,9 +534,7 @@ omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, ((u32 *)xfer->rx_buf)[elements] = w; ((u32 *)xfer->rx_buf)[elements] = w; } else { } else { dev_err(&spi->dev, "DMA RX last word empty"); dev_err(&spi->dev, "DMA RX last word empty"); count -= (word_len <= 8) ? 1 : count -= mcspi_bytes_per_word(word_len); (word_len <= 16) ? 2 : /* word_len <= 32 */ 4; } } omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 1); return count; return count; Loading @@ -475,7 +553,10 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) struct dma_slave_config cfg; struct dma_slave_config cfg; enum dma_slave_buswidth width; enum dma_slave_buswidth width; unsigned es; unsigned es; u32 burst; void __iomem *chstat_reg; void __iomem *chstat_reg; void __iomem *irqstat_reg; int wait_res; mcspi = spi_master_get_devdata(spi->master); mcspi = spi_master_get_devdata(spi->master); mcspi_dma = &mcspi->dma_channels[spi->chip_select]; mcspi_dma = &mcspi->dma_channels[spi->chip_select]; Loading @@ -493,19 +574,27 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) es = 4; es = 4; } } count = xfer->len; burst = 1; if (mcspi->fifo_depth > 0) { if (count > mcspi->fifo_depth) burst = mcspi->fifo_depth / es; else burst = count / es; } memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg)); cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; cfg.src_addr_width = width; cfg.src_addr_width = width; cfg.dst_addr_width = width; cfg.dst_addr_width = width; cfg.src_maxburst = 1; cfg.src_maxburst = burst; cfg.dst_maxburst = 1; cfg.dst_maxburst = burst; rx = xfer->rx_buf; rx = xfer->rx_buf; tx = xfer->tx_buf; tx = xfer->tx_buf; count = xfer->len; if (tx != NULL) if (tx != NULL) omap2_mcspi_tx_dma(spi, xfer, cfg); omap2_mcspi_tx_dma(spi, xfer, cfg); Loading @@ -513,18 +602,38 @@ omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); if (tx != NULL) { if (tx != NULL) { chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; wait_for_completion(&mcspi_dma->dma_tx_completion); wait_for_completion(&mcspi_dma->dma_tx_completion); dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len, dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len, DMA_TO_DEVICE); DMA_TO_DEVICE); if (mcspi->fifo_depth > 0) { irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; if (mcspi_wait_for_reg_bit(irqstat_reg, OMAP2_MCSPI_IRQSTATUS_EOW) < 0) dev_err(&spi->dev, "EOW timed out\n"); mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS, OMAP2_MCSPI_IRQSTATUS_EOW); } /* for TX_ONLY mode, be sure all words have shifted out */ /* for TX_ONLY mode, be sure all words have shifted out */ if (rx == NULL) { if (rx == NULL) { if (mcspi_wait_for_reg_bit(chstat_reg, chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; OMAP2_MCSPI_CHSTAT_TXS) < 0) if (mcspi->fifo_depth > 0) { wait_res = mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXFFE); if (wait_res < 0) dev_err(&spi->dev, "TXFFE timed out\n"); } else { wait_res = mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_TXS); if (wait_res < 0) dev_err(&spi->dev, "TXS timed out\n"); dev_err(&spi->dev, "TXS timed out\n"); else if (mcspi_wait_for_reg_bit(chstat_reg, } OMAP2_MCSPI_CHSTAT_EOT) < 0) if (wait_res >= 0 && (mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_EOT) < 0)) dev_err(&spi->dev, "EOT timed out\n"); dev_err(&spi->dev, "EOT timed out\n"); } } } } Loading Loading @@ -830,12 +939,20 @@ static int omap2_mcspi_request_dma(struct spi_device *spi) dma_cap_zero(mask); dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_SLAVE, mask); sig = mcspi_dma->dma_rx_sync_dev; sig = mcspi_dma->dma_rx_sync_dev; mcspi_dma->dma_rx = dma_request_channel(mask, omap_dma_filter_fn, &sig); mcspi_dma->dma_rx = dma_request_slave_channel_compat(mask, omap_dma_filter_fn, &sig, &master->dev, mcspi_dma->dma_rx_ch_name); if (!mcspi_dma->dma_rx) if (!mcspi_dma->dma_rx) goto no_dma; goto no_dma; sig = mcspi_dma->dma_tx_sync_dev; sig = mcspi_dma->dma_tx_sync_dev; mcspi_dma->dma_tx = dma_request_channel(mask, omap_dma_filter_fn, &sig); mcspi_dma->dma_tx = dma_request_slave_channel_compat(mask, omap_dma_filter_fn, &sig, &master->dev, mcspi_dma->dma_tx_ch_name); if (!mcspi_dma->dma_tx) { if (!mcspi_dma->dma_tx) { dma_release_channel(mcspi_dma->dma_rx); dma_release_channel(mcspi_dma->dma_rx); mcspi_dma->dma_rx = NULL; mcspi_dma->dma_rx = NULL; Loading Loading @@ -945,7 +1062,7 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) cs = spi->controller_state; cs = spi->controller_state; cd = spi->controller_data; cd = spi->controller_data; omap2_mcspi_set_enable(spi, 1); omap2_mcspi_set_enable(spi, 0); list_for_each_entry(t, &m->transfers, transfer_list) { list_for_each_entry(t, &m->transfers, transfer_list) { if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { status = -EINVAL; status = -EINVAL; Loading Loading @@ -993,6 +1110,12 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) if (t->len) { if (t->len) { unsigned count; unsigned count; if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)) omap2_mcspi_set_fifo(spi, t, 1); omap2_mcspi_set_enable(spi, 1); /* RX_ONLY mode needs dummy data in TX reg */ /* RX_ONLY mode needs dummy data in TX reg */ if (t->tx_buf == NULL) if (t->tx_buf == NULL) __raw_writel(0, cs->base __raw_writel(0, cs->base Loading @@ -1019,6 +1142,11 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) omap2_mcspi_force_cs(spi, 0); omap2_mcspi_force_cs(spi, 0); cs_active = 0; cs_active = 0; } } omap2_mcspi_set_enable(spi, 0); if (mcspi->fifo_depth > 0) omap2_mcspi_set_fifo(spi, t, 0); } } /* Restore defaults if they were overriden */ /* Restore defaults if they were overriden */ if (par_override) { if (par_override) { Loading @@ -1039,8 +1167,10 @@ static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) omap2_mcspi_set_enable(spi, 0); omap2_mcspi_set_enable(spi, 0); m->status = status; if (mcspi->fifo_depth > 0 && t) omap2_mcspi_set_fifo(spi, t, 0); m->status = status; } } static int omap2_mcspi_transfer_one_message(struct spi_master *master, static int omap2_mcspi_transfer_one_message(struct spi_master *master, Loading Loading @@ -1177,7 +1307,6 @@ static int omap2_mcspi_probe(struct platform_device *pdev) static int bus_num = 1; static int bus_num = 1; struct device_node *node = pdev->dev.of_node; struct device_node *node = pdev->dev.of_node; const struct of_device_id *match; const struct of_device_id *match; struct pinctrl *pinctrl; master = spi_alloc_master(&pdev->dev, sizeof *mcspi); master = spi_alloc_master(&pdev->dev, sizeof *mcspi); if (master == NULL) { if (master == NULL) { Loading Loading @@ -1247,39 +1376,47 @@ static int omap2_mcspi_probe(struct platform_device *pdev) goto free_master; goto free_master; for (i = 0; i < master->num_chipselect; i++) { for (i = 0; i < master->num_chipselect; i++) { char dma_ch_name[14]; char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name; char *dma_tx_ch_name = mcspi->dma_channels[i].dma_tx_ch_name; struct resource *dma_res; struct resource *dma_res; sprintf(dma_ch_name, "rx%d", i); sprintf(dma_rx_ch_name, "rx%d", i); dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, if (!pdev->dev.of_node) { dma_ch_name); dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, dma_rx_ch_name); if (!dma_res) { if (!dma_res) { dev_dbg(&pdev->dev, "cannot get DMA RX channel\n"); dev_dbg(&pdev->dev, "cannot get DMA RX channel\n"); status = -ENODEV; status = -ENODEV; break; break; } } mcspi->dma_channels[i].dma_rx_sync_dev = dma_res->start; mcspi->dma_channels[i].dma_rx_sync_dev = sprintf(dma_ch_name, "tx%d", i); dma_res->start; dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, } dma_ch_name); sprintf(dma_tx_ch_name, "tx%d", i); if (!pdev->dev.of_node) { dma_res = platform_get_resource_byname(pdev, IORESOURCE_DMA, dma_tx_ch_name); if (!dma_res) { if (!dma_res) { dev_dbg(&pdev->dev, "cannot get DMA TX channel\n"); dev_dbg(&pdev->dev, "cannot get DMA TX channel\n"); status = -ENODEV; status = -ENODEV; break; break; } } mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; mcspi->dma_channels[i].dma_tx_sync_dev = dma_res->start; } } } if (status < 0) if (status < 0) goto dma_chnl_free; goto dma_chnl_free; pinctrl = devm_pinctrl_get_select_default(&pdev->dev); if (IS_ERR(pinctrl)) dev_warn(&pdev->dev, "pins are not configured from the driver\n"); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev); Loading