1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 2ca632f55SGrant Likely /* 3ca632f55SGrant Likely * OMAP2 McSPI controller driver 4ca632f55SGrant Likely * 5ca632f55SGrant Likely * Copyright (C) 2005, 2006 Nokia Corporation 6ca632f55SGrant Likely * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and 76328caf0SMauro Carvalho Chehab * Juha Yrjola <juha.yrjola@nokia.com> 8ca632f55SGrant Likely */ 9ca632f55SGrant Likely 10ca632f55SGrant Likely #include <linux/kernel.h> 11ca632f55SGrant Likely #include <linux/interrupt.h> 12ca632f55SGrant Likely #include <linux/module.h> 13ca632f55SGrant Likely #include <linux/device.h> 14ca632f55SGrant Likely #include <linux/delay.h> 15ca632f55SGrant Likely #include <linux/dma-mapping.h> 1653741ed8SRussell King #include <linux/dmaengine.h> 17beca3655SPascal Huerst #include <linux/pinctrl/consumer.h> 18ca632f55SGrant Likely #include <linux/platform_device.h> 19ca632f55SGrant Likely #include <linux/err.h> 20ca632f55SGrant Likely #include <linux/clk.h> 21ca632f55SGrant Likely #include <linux/io.h> 22ca632f55SGrant Likely #include <linux/slab.h> 23ca632f55SGrant Likely #include <linux/pm_runtime.h> 24d5a80031SBenoit Cousson #include <linux/of.h> 25d5a80031SBenoit Cousson #include <linux/of_device.h> 26d33f473dSIllia Smyrnov #include <linux/gcd.h> 27ca632f55SGrant Likely 28ca632f55SGrant Likely #include <linux/spi/spi.h> 29ca632f55SGrant Likely 302203747cSArnd Bergmann #include <linux/platform_data/spi-omap2-mcspi.h> 31ca632f55SGrant Likely 32ca632f55SGrant Likely #define OMAP2_MCSPI_MAX_FREQ 48000000 33faee9b05SStefan Sørensen #define OMAP2_MCSPI_MAX_DIVIDER 4096 34d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFODEPTH 64 35d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF 3627b5284cSShubhrajyoti D #define SPI_AUTOSUSPEND_TIMEOUT 2000 37ca632f55SGrant Likely 38ca632f55SGrant Likely #define OMAP2_MCSPI_REVISION 0x00 39ca632f55SGrant Likely #define OMAP2_MCSPI_SYSSTATUS 0x14 40ca632f55SGrant Likely #define OMAP2_MCSPI_IRQSTATUS 0x18 41ca632f55SGrant Likely #define OMAP2_MCSPI_IRQENABLE 0x1c 42ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE 0x20 43ca632f55SGrant Likely #define OMAP2_MCSPI_SYST 0x24 44ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL 0x28 45d33f473dSIllia Smyrnov #define OMAP2_MCSPI_XFERLEVEL 0x7c 46ca632f55SGrant Likely 47ca632f55SGrant Likely /* per-channel banks, 0x14 bytes each, first is: */ 48ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF0 0x2c 49ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT0 0x30 50ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL0 0x34 51ca632f55SGrant Likely #define OMAP2_MCSPI_TX0 0x38 52ca632f55SGrant Likely #define OMAP2_MCSPI_RX0 0x3c 53ca632f55SGrant Likely 54ca632f55SGrant Likely /* per-register bitmasks: */ 55d33f473dSIllia Smyrnov #define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17) 56ca632f55SGrant Likely 57ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) 58ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) 59ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_STEST BIT(3) 60ca632f55SGrant Likely 61ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_PHA BIT(0) 62ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_POL BIT(1) 63ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_CLKD_MASK (0x0f << 2) 64ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_EPOL BIT(6) 65ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_WL_MASK (0x1f << 7) 66ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY BIT(12) 67ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY BIT(13) 68ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_MASK (0x03 << 12) 69ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAW BIT(14) 70ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAR BIT(15) 71ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE0 BIT(16) 72ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE1 BIT(17) 73ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_IS BIT(18) 74ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) 75ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) 76d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFET BIT(27) 77d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFER BIT(28) 78faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCONF_CLKG BIT(29) 79ca632f55SGrant Likely 80ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) 81ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) 82ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) 83d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) 84ca632f55SGrant Likely 85ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL_EN BIT(0) 86faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8) 87ca632f55SGrant Likely 88ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) 89ca632f55SGrant Likely 90ca632f55SGrant Likely /* We have 2 DMA channels per CS, one for RX and one for TX */ 91ca632f55SGrant Likely struct omap2_mcspi_dma { 9253741ed8SRussell King struct dma_chan *dma_tx; 9353741ed8SRussell King struct dma_chan *dma_rx; 94ca632f55SGrant Likely 95ca632f55SGrant Likely struct completion dma_tx_completion; 96ca632f55SGrant Likely struct completion dma_rx_completion; 9774f3aaadSMatt Porter 9874f3aaadSMatt Porter char dma_rx_ch_name[14]; 9974f3aaadSMatt Porter char dma_tx_ch_name[14]; 100ca632f55SGrant Likely }; 101ca632f55SGrant Likely 102ca632f55SGrant Likely /* use PIO for small transfers, avoiding DMA setup/teardown overhead and 103ca632f55SGrant Likely * cache operations; better heuristics consider wordsize and bitrate. 104ca632f55SGrant Likely */ 105ca632f55SGrant Likely #define DMA_MIN_BYTES 160 106ca632f55SGrant Likely 107ca632f55SGrant Likely 1081bd897f8SBenoit Cousson /* 1091bd897f8SBenoit Cousson * Used for context save and restore, structure members to be updated whenever 1101bd897f8SBenoit Cousson * corresponding registers are modified. 1111bd897f8SBenoit Cousson */ 1121bd897f8SBenoit Cousson struct omap2_mcspi_regs { 1131bd897f8SBenoit Cousson u32 modulctrl; 1141bd897f8SBenoit Cousson u32 wakeupenable; 1151bd897f8SBenoit Cousson struct list_head cs; 1161bd897f8SBenoit Cousson }; 1171bd897f8SBenoit Cousson 118ca632f55SGrant Likely struct omap2_mcspi { 11989e8b9cbSVignesh R struct completion txdone; 120ee0f793cSYang Yingliang struct spi_controller *ctlr; 121ca632f55SGrant Likely /* Virtual base address of the controller */ 122ca632f55SGrant Likely void __iomem *base; 123ca632f55SGrant Likely unsigned long phys; 124ca632f55SGrant Likely /* SPI1 has 4 channels, while SPI2 has 2 */ 125ca632f55SGrant Likely struct omap2_mcspi_dma *dma_channels; 126ca632f55SGrant Likely struct device *dev; 1271bd897f8SBenoit Cousson struct omap2_mcspi_regs ctx; 128*2d9f4877SVaishnav Achath struct clk *ref_clk; 129d33f473dSIllia Smyrnov int fifo_depth; 130ee0f793cSYang Yingliang bool target_aborted; 1310384e90bSDaniel Mack unsigned int pin_dir:1; 132e4e8276aSVignesh Raghavendra size_t max_xfer_len; 133*2d9f4877SVaishnav Achath u32 ref_clk_hz; 134ca632f55SGrant Likely }; 135ca632f55SGrant Likely 136ca632f55SGrant Likely struct omap2_mcspi_cs { 137ca632f55SGrant Likely void __iomem *base; 138ca632f55SGrant Likely unsigned long phys; 139ca632f55SGrant Likely int word_len; 14097ca0d6cSMark A. Greer u16 mode; 141ca632f55SGrant Likely struct list_head node; 142ca632f55SGrant Likely /* Context save and restore shadow register */ 143faee9b05SStefan Sørensen u32 chconf0, chctrl0; 144ca632f55SGrant Likely }; 145ca632f55SGrant Likely 146ee0f793cSYang Yingliang static inline void mcspi_write_reg(struct spi_controller *ctlr, 147ca632f55SGrant Likely int idx, u32 val) 148ca632f55SGrant Likely { 149ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 150ca632f55SGrant Likely 15121b2ce5eSVictor Kamensky writel_relaxed(val, mcspi->base + idx); 152ca632f55SGrant Likely } 153ca632f55SGrant Likely 154ee0f793cSYang Yingliang static inline u32 mcspi_read_reg(struct spi_controller *ctlr, int idx) 155ca632f55SGrant Likely { 156ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 157ca632f55SGrant Likely 15821b2ce5eSVictor Kamensky return readl_relaxed(mcspi->base + idx); 159ca632f55SGrant Likely } 160ca632f55SGrant Likely 161ca632f55SGrant Likely static inline void mcspi_write_cs_reg(const struct spi_device *spi, 162ca632f55SGrant Likely int idx, u32 val) 163ca632f55SGrant Likely { 164ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 165ca632f55SGrant Likely 16621b2ce5eSVictor Kamensky writel_relaxed(val, cs->base + idx); 167ca632f55SGrant Likely } 168ca632f55SGrant Likely 169ca632f55SGrant Likely static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx) 170ca632f55SGrant Likely { 171ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 172ca632f55SGrant Likely 17321b2ce5eSVictor Kamensky return readl_relaxed(cs->base + idx); 174ca632f55SGrant Likely } 175ca632f55SGrant Likely 176ca632f55SGrant Likely static inline u32 mcspi_cached_chconf0(const struct spi_device *spi) 177ca632f55SGrant Likely { 178ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 179ca632f55SGrant Likely 180ca632f55SGrant Likely return cs->chconf0; 181ca632f55SGrant Likely } 182ca632f55SGrant Likely 183ca632f55SGrant Likely static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val) 184ca632f55SGrant Likely { 185ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 186ca632f55SGrant Likely 187ca632f55SGrant Likely cs->chconf0 = val; 188ca632f55SGrant Likely mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val); 189ca632f55SGrant Likely mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); 190ca632f55SGrant Likely } 191ca632f55SGrant Likely 19256cd5c15SIllia Smyrnov static inline int mcspi_bytes_per_word(int word_len) 19356cd5c15SIllia Smyrnov { 19456cd5c15SIllia Smyrnov if (word_len <= 8) 19556cd5c15SIllia Smyrnov return 1; 19656cd5c15SIllia Smyrnov else if (word_len <= 16) 19756cd5c15SIllia Smyrnov return 2; 19856cd5c15SIllia Smyrnov else /* word_len <= 32 */ 19956cd5c15SIllia Smyrnov return 4; 20056cd5c15SIllia Smyrnov } 20156cd5c15SIllia Smyrnov 202ca632f55SGrant Likely static void omap2_mcspi_set_dma_req(const struct spi_device *spi, 203ca632f55SGrant Likely int is_read, int enable) 204ca632f55SGrant Likely { 205ca632f55SGrant Likely u32 l, rw; 206ca632f55SGrant Likely 207ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 208ca632f55SGrant Likely 209ca632f55SGrant Likely if (is_read) /* 1 is read, 0 write */ 210ca632f55SGrant Likely rw = OMAP2_MCSPI_CHCONF_DMAR; 211ca632f55SGrant Likely else 212ca632f55SGrant Likely rw = OMAP2_MCSPI_CHCONF_DMAW; 213ca632f55SGrant Likely 214af4e944dSShubhrajyoti D if (enable) 215af4e944dSShubhrajyoti D l |= rw; 216af4e944dSShubhrajyoti D else 217af4e944dSShubhrajyoti D l &= ~rw; 218af4e944dSShubhrajyoti D 219ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 220ca632f55SGrant Likely } 221ca632f55SGrant Likely 222ca632f55SGrant Likely static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) 223ca632f55SGrant Likely { 224faee9b05SStefan Sørensen struct omap2_mcspi_cs *cs = spi->controller_state; 225ca632f55SGrant Likely u32 l; 226ca632f55SGrant Likely 227faee9b05SStefan Sørensen l = cs->chctrl0; 228faee9b05SStefan Sørensen if (enable) 229faee9b05SStefan Sørensen l |= OMAP2_MCSPI_CHCTRL_EN; 230faee9b05SStefan Sørensen else 231faee9b05SStefan Sørensen l &= ~OMAP2_MCSPI_CHCTRL_EN; 232faee9b05SStefan Sørensen cs->chctrl0 = l; 233faee9b05SStefan Sørensen mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); 234ca632f55SGrant Likely /* Flash post-writes */ 235ca632f55SGrant Likely mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); 236ca632f55SGrant Likely } 237ca632f55SGrant Likely 238ddcad7e9SMichael Welling static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) 239ca632f55SGrant Likely { 240ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller); 241ca632f55SGrant Likely u32 l; 242ca632f55SGrant Likely 2434373f8b6SMichael Welling /* The controller handles the inverted chip selects 2444373f8b6SMichael Welling * using the OMAP2_MCSPI_CHCONF_EPOL bit so revert 2454373f8b6SMichael Welling * the inversion from the core spi_set_cs function. 2464373f8b6SMichael Welling */ 2474373f8b6SMichael Welling if (spi->mode & SPI_CS_HIGH) 2484373f8b6SMichael Welling enable = !enable; 2494373f8b6SMichael Welling 250ddcad7e9SMichael Welling if (spi->controller_state) { 25140b6a137SMinghao Chi int err = pm_runtime_resume_and_get(mcspi->dev); 2525f74db10SSebastian Reichel if (err < 0) { 2535f74db10SSebastian Reichel dev_err(mcspi->dev, "failed to get sync: %d\n", err); 2545f74db10SSebastian Reichel return; 2555f74db10SSebastian Reichel } 2565f74db10SSebastian Reichel 257ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 258ddcad7e9SMichael Welling 259ddcad7e9SMichael Welling if (enable) 260af4e944dSShubhrajyoti D l &= ~OMAP2_MCSPI_CHCONF_FORCE; 261ddcad7e9SMichael Welling else 262ddcad7e9SMichael Welling l |= OMAP2_MCSPI_CHCONF_FORCE; 263af4e944dSShubhrajyoti D 264ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 2655f74db10SSebastian Reichel 2665f74db10SSebastian Reichel pm_runtime_mark_last_busy(mcspi->dev); 2675f74db10SSebastian Reichel pm_runtime_put_autosuspend(mcspi->dev); 268ca632f55SGrant Likely } 269ddcad7e9SMichael Welling } 270ca632f55SGrant Likely 271ee0f793cSYang Yingliang static void omap2_mcspi_set_mode(struct spi_controller *ctlr) 272ca632f55SGrant Likely { 273ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 2741bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 275ca632f55SGrant Likely u32 l; 276ca632f55SGrant Likely 2771bd897f8SBenoit Cousson /* 278ee0f793cSYang Yingliang * Choose host or target mode 279ca632f55SGrant Likely */ 280ee0f793cSYang Yingliang l = mcspi_read_reg(ctlr, OMAP2_MCSPI_MODULCTRL); 28189e8b9cbSVignesh R l &= ~(OMAP2_MCSPI_MODULCTRL_STEST); 282ee0f793cSYang Yingliang if (spi_controller_is_target(ctlr)) { 28389e8b9cbSVignesh R l |= (OMAP2_MCSPI_MODULCTRL_MS); 28489e8b9cbSVignesh R } else { 28589e8b9cbSVignesh R l &= ~(OMAP2_MCSPI_MODULCTRL_MS); 286af4e944dSShubhrajyoti D l |= OMAP2_MCSPI_MODULCTRL_SINGLE; 28789e8b9cbSVignesh R } 288ee0f793cSYang Yingliang mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, l); 289ca632f55SGrant Likely 2901bd897f8SBenoit Cousson ctx->modulctrl = l; 291ca632f55SGrant Likely } 292ca632f55SGrant Likely 293d33f473dSIllia Smyrnov static void omap2_mcspi_set_fifo(const struct spi_device *spi, 294d33f473dSIllia Smyrnov struct spi_transfer *t, int enable) 295d33f473dSIllia Smyrnov { 296ee0f793cSYang Yingliang struct spi_controller *ctlr = spi->controller; 297d33f473dSIllia Smyrnov struct omap2_mcspi_cs *cs = spi->controller_state; 298d33f473dSIllia Smyrnov struct omap2_mcspi *mcspi; 299d33f473dSIllia Smyrnov unsigned int wcnt; 300b682cffaSVignesh R int max_fifo_depth, bytes_per_word; 301d33f473dSIllia Smyrnov u32 chconf, xferlevel; 302d33f473dSIllia Smyrnov 303ee0f793cSYang Yingliang mcspi = spi_controller_get_devdata(ctlr); 304d33f473dSIllia Smyrnov 305d33f473dSIllia Smyrnov chconf = mcspi_cached_chconf0(spi); 306d33f473dSIllia Smyrnov if (enable) { 307d33f473dSIllia Smyrnov bytes_per_word = mcspi_bytes_per_word(cs->word_len); 308d33f473dSIllia Smyrnov if (t->len % bytes_per_word != 0) 309d33f473dSIllia Smyrnov goto disable_fifo; 310d33f473dSIllia Smyrnov 3115db542edSIllia Smyrnov if (t->rx_buf != NULL && t->tx_buf != NULL) 3125db542edSIllia Smyrnov max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2; 3135db542edSIllia Smyrnov else 3145db542edSIllia Smyrnov max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; 3155db542edSIllia Smyrnov 316d33f473dSIllia Smyrnov wcnt = t->len / bytes_per_word; 317d33f473dSIllia Smyrnov if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) 318d33f473dSIllia Smyrnov goto disable_fifo; 319d33f473dSIllia Smyrnov 320d33f473dSIllia Smyrnov xferlevel = wcnt << 16; 321d33f473dSIllia Smyrnov if (t->rx_buf != NULL) { 322d33f473dSIllia Smyrnov chconf |= OMAP2_MCSPI_CHCONF_FFER; 323b682cffaSVignesh R xferlevel |= (bytes_per_word - 1) << 8; 3245db542edSIllia Smyrnov } 325b682cffaSVignesh R 3265db542edSIllia Smyrnov if (t->tx_buf != NULL) { 327d33f473dSIllia Smyrnov chconf |= OMAP2_MCSPI_CHCONF_FFET; 328b682cffaSVignesh R xferlevel |= bytes_per_word - 1; 329d33f473dSIllia Smyrnov } 330d33f473dSIllia Smyrnov 331ee0f793cSYang Yingliang mcspi_write_reg(ctlr, OMAP2_MCSPI_XFERLEVEL, xferlevel); 332d33f473dSIllia Smyrnov mcspi_write_chconf0(spi, chconf); 333b682cffaSVignesh R mcspi->fifo_depth = max_fifo_depth; 334d33f473dSIllia Smyrnov 335d33f473dSIllia Smyrnov return; 336d33f473dSIllia Smyrnov } 337d33f473dSIllia Smyrnov 338d33f473dSIllia Smyrnov disable_fifo: 339d33f473dSIllia Smyrnov if (t->rx_buf != NULL) 340d33f473dSIllia Smyrnov chconf &= ~OMAP2_MCSPI_CHCONF_FFER; 3413d0763c0SJorge A. Ventura 3423d0763c0SJorge A. Ventura if (t->tx_buf != NULL) 343d33f473dSIllia Smyrnov chconf &= ~OMAP2_MCSPI_CHCONF_FFET; 344d33f473dSIllia Smyrnov 345d33f473dSIllia Smyrnov mcspi_write_chconf0(spi, chconf); 346d33f473dSIllia Smyrnov mcspi->fifo_depth = 0; 347d33f473dSIllia Smyrnov } 348d33f473dSIllia Smyrnov 349ca632f55SGrant Likely static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) 350ca632f55SGrant Likely { 3517b1d9681SAswath Govindraju unsigned long timeout; 352ca632f55SGrant Likely 3537b1d9681SAswath Govindraju timeout = jiffies + msecs_to_jiffies(1000); 3547b1d9681SAswath Govindraju while (!(readl_relaxed(reg) & bit)) { 3557b1d9681SAswath Govindraju if (time_after(jiffies, timeout)) { 3567b1d9681SAswath Govindraju if (!(readl_relaxed(reg) & bit)) 3577b1d9681SAswath Govindraju return -ETIMEDOUT; 3587b1d9681SAswath Govindraju else 3597b1d9681SAswath Govindraju return 0; 3607b1d9681SAswath Govindraju } 3617b1d9681SAswath Govindraju cpu_relax(); 3627b1d9681SAswath Govindraju } 3637b1d9681SAswath Govindraju return 0; 364ca632f55SGrant Likely } 365ca632f55SGrant Likely 36689e8b9cbSVignesh R static int mcspi_wait_for_completion(struct omap2_mcspi *mcspi, 36789e8b9cbSVignesh R struct completion *x) 36889e8b9cbSVignesh R { 369ee0f793cSYang Yingliang if (spi_controller_is_target(mcspi->ctlr)) { 37089e8b9cbSVignesh R if (wait_for_completion_interruptible(x) || 371ee0f793cSYang Yingliang mcspi->target_aborted) 37289e8b9cbSVignesh R return -EINTR; 37389e8b9cbSVignesh R } else { 37489e8b9cbSVignesh R wait_for_completion(x); 37589e8b9cbSVignesh R } 37689e8b9cbSVignesh R 37789e8b9cbSVignesh R return 0; 37889e8b9cbSVignesh R } 37989e8b9cbSVignesh R 38053741ed8SRussell King static void omap2_mcspi_rx_callback(void *data) 38153741ed8SRussell King { 38253741ed8SRussell King struct spi_device *spi = data; 383ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller); 3849e264f3fSAmit Kumar Mahapatra via Alsa-devel struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)]; 38553741ed8SRussell King 38653741ed8SRussell King /* We must disable the DMA RX request */ 38753741ed8SRussell King omap2_mcspi_set_dma_req(spi, 1, 0); 388830379e0SFelipe Balbi 389830379e0SFelipe Balbi complete(&mcspi_dma->dma_rx_completion); 39053741ed8SRussell King } 39153741ed8SRussell King 39253741ed8SRussell King static void omap2_mcspi_tx_callback(void *data) 39353741ed8SRussell King { 39453741ed8SRussell King struct spi_device *spi = data; 395ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller); 3969e264f3fSAmit Kumar Mahapatra via Alsa-devel struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)]; 39753741ed8SRussell King 39853741ed8SRussell King /* We must disable the DMA TX request */ 39953741ed8SRussell King omap2_mcspi_set_dma_req(spi, 0, 0); 400830379e0SFelipe Balbi 401830379e0SFelipe Balbi complete(&mcspi_dma->dma_tx_completion); 40253741ed8SRussell King } 40353741ed8SRussell King 404d7b4394eSShubhrajyoti D static void omap2_mcspi_tx_dma(struct spi_device *spi, 405d7b4394eSShubhrajyoti D struct spi_transfer *xfer, 406d7b4394eSShubhrajyoti D struct dma_slave_config cfg) 407ca632f55SGrant Likely { 408ca632f55SGrant Likely struct omap2_mcspi *mcspi; 409ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 4108d858491SVignesh Raghavendra struct dma_async_tx_descriptor *tx; 411ca632f55SGrant Likely 412ee0f793cSYang Yingliang mcspi = spi_controller_get_devdata(spi->controller); 4139e264f3fSAmit Kumar Mahapatra via Alsa-devel mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)]; 414ca632f55SGrant Likely 41553741ed8SRussell King dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); 41653741ed8SRussell King 4170ba1870fSFranklin S Cooper Jr tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl, 4180ba1870fSFranklin S Cooper Jr xfer->tx_sg.nents, 4190ba1870fSFranklin S Cooper Jr DMA_MEM_TO_DEV, 4200ba1870fSFranklin S Cooper Jr DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 42153741ed8SRussell King if (tx) { 42253741ed8SRussell King tx->callback = omap2_mcspi_tx_callback; 42353741ed8SRussell King tx->callback_param = spi; 42453741ed8SRussell King dmaengine_submit(tx); 42553741ed8SRussell King } else { 42653741ed8SRussell King /* FIXME: fall back to PIO? */ 42753741ed8SRussell King } 42853741ed8SRussell King dma_async_issue_pending(mcspi_dma->dma_tx); 429ca632f55SGrant Likely omap2_mcspi_set_dma_req(spi, 0, 1); 430ca632f55SGrant Likely } 431ca632f55SGrant Likely 432d7b4394eSShubhrajyoti D static unsigned 433d7b4394eSShubhrajyoti D omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, 434d7b4394eSShubhrajyoti D struct dma_slave_config cfg, 435d7b4394eSShubhrajyoti D unsigned es) 436d7b4394eSShubhrajyoti D { 437d7b4394eSShubhrajyoti D struct omap2_mcspi *mcspi; 438d7b4394eSShubhrajyoti D struct omap2_mcspi_dma *mcspi_dma; 4390ba1870fSFranklin S Cooper Jr unsigned int count, transfer_reduction = 0; 4400ba1870fSFranklin S Cooper Jr struct scatterlist *sg_out[2]; 4410ba1870fSFranklin S Cooper Jr int nb_sizes = 0, out_mapped_nents[2], ret, x; 4420ba1870fSFranklin S Cooper Jr size_t sizes[2]; 443d7b4394eSShubhrajyoti D u32 l; 444d7b4394eSShubhrajyoti D int elements = 0; 445d7b4394eSShubhrajyoti D int word_len, element_count; 446d7b4394eSShubhrajyoti D struct omap2_mcspi_cs *cs = spi->controller_state; 44781261359SAkinobu Mita void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; 4488d858491SVignesh Raghavendra struct dma_async_tx_descriptor *tx; 44981261359SAkinobu Mita 450ee0f793cSYang Yingliang mcspi = spi_controller_get_devdata(spi->controller); 4519e264f3fSAmit Kumar Mahapatra via Alsa-devel mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)]; 452d7b4394eSShubhrajyoti D count = xfer->len; 453d33f473dSIllia Smyrnov 4544bd00413SFranklin S Cooper Jr /* 4554bd00413SFranklin S Cooper Jr * In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM 456ee0f793cSYang Yingliang * it mentions reducing DMA transfer length by one element in host 4574bd00413SFranklin S Cooper Jr * normal mode. 4584bd00413SFranklin S Cooper Jr */ 459d33f473dSIllia Smyrnov if (mcspi->fifo_depth == 0) 4600ba1870fSFranklin S Cooper Jr transfer_reduction = es; 461d33f473dSIllia Smyrnov 462d7b4394eSShubhrajyoti D word_len = cs->word_len; 463d7b4394eSShubhrajyoti D l = mcspi_cached_chconf0(spi); 464d7b4394eSShubhrajyoti D 465d7b4394eSShubhrajyoti D if (word_len <= 8) 466d7b4394eSShubhrajyoti D element_count = count; 467d7b4394eSShubhrajyoti D else if (word_len <= 16) 468d7b4394eSShubhrajyoti D element_count = count >> 1; 469d7b4394eSShubhrajyoti D else /* word_len <= 32 */ 470d7b4394eSShubhrajyoti D element_count = count >> 2; 471d7b4394eSShubhrajyoti D 472d7b4394eSShubhrajyoti D 473d7b4394eSShubhrajyoti D dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); 474d7b4394eSShubhrajyoti D 4754bd00413SFranklin S Cooper Jr /* 4764bd00413SFranklin S Cooper Jr * Reduce DMA transfer length by one more if McSPI is 4774bd00413SFranklin S Cooper Jr * configured in turbo mode. 4784bd00413SFranklin S Cooper Jr */ 479d33f473dSIllia Smyrnov if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) 4800ba1870fSFranklin S Cooper Jr transfer_reduction += es; 481d7b4394eSShubhrajyoti D 4820ba1870fSFranklin S Cooper Jr if (transfer_reduction) { 4830ba1870fSFranklin S Cooper Jr /* Split sgl into two. The second sgl won't be used. */ 4840ba1870fSFranklin S Cooper Jr sizes[0] = count - transfer_reduction; 4850ba1870fSFranklin S Cooper Jr sizes[1] = transfer_reduction; 4860ba1870fSFranklin S Cooper Jr nb_sizes = 2; 4870ba1870fSFranklin S Cooper Jr } else { 4880ba1870fSFranklin S Cooper Jr /* 4890ba1870fSFranklin S Cooper Jr * Don't bother splitting the sgl. This essentially 4900ba1870fSFranklin S Cooper Jr * clones the original sgl. 4910ba1870fSFranklin S Cooper Jr */ 4920ba1870fSFranklin S Cooper Jr sizes[0] = count; 4930ba1870fSFranklin S Cooper Jr nb_sizes = 1; 4940ba1870fSFranklin S Cooper Jr } 495d7b4394eSShubhrajyoti D 4968d858491SVignesh Raghavendra ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 0, nb_sizes, 4978d858491SVignesh Raghavendra sizes, sg_out, out_mapped_nents, GFP_KERNEL); 4980ba1870fSFranklin S Cooper Jr 4990ba1870fSFranklin S Cooper Jr if (ret < 0) { 5000ba1870fSFranklin S Cooper Jr dev_err(&spi->dev, "sg_split failed\n"); 5010ba1870fSFranklin S Cooper Jr return 0; 5020ba1870fSFranklin S Cooper Jr } 5030ba1870fSFranklin S Cooper Jr 5048d858491SVignesh Raghavendra tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, sg_out[0], 5058d858491SVignesh Raghavendra out_mapped_nents[0], DMA_DEV_TO_MEM, 5060ba1870fSFranklin S Cooper Jr DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 507d7b4394eSShubhrajyoti D if (tx) { 508d7b4394eSShubhrajyoti D tx->callback = omap2_mcspi_rx_callback; 509d7b4394eSShubhrajyoti D tx->callback_param = spi; 510d7b4394eSShubhrajyoti D dmaengine_submit(tx); 511d7b4394eSShubhrajyoti D } else { 512d7b4394eSShubhrajyoti D /* FIXME: fall back to PIO? */ 513d7b4394eSShubhrajyoti D } 514d7b4394eSShubhrajyoti D 515d7b4394eSShubhrajyoti D dma_async_issue_pending(mcspi_dma->dma_rx); 516d7b4394eSShubhrajyoti D omap2_mcspi_set_dma_req(spi, 1, 1); 517d7b4394eSShubhrajyoti D 51889e8b9cbSVignesh R ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion); 519ee0f793cSYang Yingliang if (ret || mcspi->target_aborted) { 52089e8b9cbSVignesh R dmaengine_terminate_sync(mcspi_dma->dma_rx); 52189e8b9cbSVignesh R omap2_mcspi_set_dma_req(spi, 1, 0); 52289e8b9cbSVignesh R return 0; 52389e8b9cbSVignesh R } 5240ba1870fSFranklin S Cooper Jr 5250ba1870fSFranklin S Cooper Jr for (x = 0; x < nb_sizes; x++) 5260ba1870fSFranklin S Cooper Jr kfree(sg_out[x]); 527d33f473dSIllia Smyrnov 528d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) 529d33f473dSIllia Smyrnov return count; 530d33f473dSIllia Smyrnov 5314bd00413SFranklin S Cooper Jr /* 5324bd00413SFranklin S Cooper Jr * Due to the DMA transfer length reduction the missing bytes must 5334bd00413SFranklin S Cooper Jr * be read manually to receive all of the expected data. 5344bd00413SFranklin S Cooper Jr */ 535ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 536ca632f55SGrant Likely 53753741ed8SRussell King elements = element_count - 1; 53853741ed8SRussell King 539ca632f55SGrant Likely if (l & OMAP2_MCSPI_CHCONF_TURBO) { 54053741ed8SRussell King elements--; 541ca632f55SGrant Likely 54281261359SAkinobu Mita if (!mcspi_wait_for_reg_bit(chstat_reg, 54381261359SAkinobu Mita OMAP2_MCSPI_CHSTAT_RXS)) { 544ca632f55SGrant Likely u32 w; 545ca632f55SGrant Likely 546ca632f55SGrant Likely w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); 547ca632f55SGrant Likely if (word_len <= 8) 548ca632f55SGrant Likely ((u8 *)xfer->rx_buf)[elements++] = w; 549ca632f55SGrant Likely else if (word_len <= 16) 550ca632f55SGrant Likely ((u16 *)xfer->rx_buf)[elements++] = w; 551ca632f55SGrant Likely else /* word_len <= 32 */ 552ca632f55SGrant Likely ((u32 *)xfer->rx_buf)[elements++] = w; 553ca632f55SGrant Likely } else { 55456cd5c15SIllia Smyrnov int bytes_per_word = mcspi_bytes_per_word(word_len); 555a1829d2bSJarkko Nikula dev_err(&spi->dev, "DMA RX penultimate word empty\n"); 55656cd5c15SIllia Smyrnov count -= (bytes_per_word << 1); 557ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 558ca632f55SGrant Likely return count; 559ca632f55SGrant Likely } 560ca632f55SGrant Likely } 56181261359SAkinobu Mita if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) { 562ca632f55SGrant Likely u32 w; 563ca632f55SGrant Likely 564ca632f55SGrant Likely w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); 565ca632f55SGrant Likely if (word_len <= 8) 566ca632f55SGrant Likely ((u8 *)xfer->rx_buf)[elements] = w; 567ca632f55SGrant Likely else if (word_len <= 16) 568ca632f55SGrant Likely ((u16 *)xfer->rx_buf)[elements] = w; 569ca632f55SGrant Likely else /* word_len <= 32 */ 570ca632f55SGrant Likely ((u32 *)xfer->rx_buf)[elements] = w; 571ca632f55SGrant Likely } else { 572a1829d2bSJarkko Nikula dev_err(&spi->dev, "DMA RX last word empty\n"); 57356cd5c15SIllia Smyrnov count -= mcspi_bytes_per_word(word_len); 574ca632f55SGrant Likely } 575ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 576d7b4394eSShubhrajyoti D return count; 577ca632f55SGrant Likely } 578d7b4394eSShubhrajyoti D 579d7b4394eSShubhrajyoti D static unsigned 580d7b4394eSShubhrajyoti D omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) 581d7b4394eSShubhrajyoti D { 582d7b4394eSShubhrajyoti D struct omap2_mcspi *mcspi; 583d7b4394eSShubhrajyoti D struct omap2_mcspi_cs *cs = spi->controller_state; 584d7b4394eSShubhrajyoti D struct omap2_mcspi_dma *mcspi_dma; 585d7b4394eSShubhrajyoti D unsigned int count; 586d7b4394eSShubhrajyoti D u8 *rx; 587d7b4394eSShubhrajyoti D const u8 *tx; 588d7b4394eSShubhrajyoti D struct dma_slave_config cfg; 589d7b4394eSShubhrajyoti D enum dma_slave_buswidth width; 590d7b4394eSShubhrajyoti D unsigned es; 591e47a682aSShubhrajyoti D void __iomem *chstat_reg; 592d33f473dSIllia Smyrnov void __iomem *irqstat_reg; 593d33f473dSIllia Smyrnov int wait_res; 594d7b4394eSShubhrajyoti D 595ee0f793cSYang Yingliang mcspi = spi_controller_get_devdata(spi->controller); 5969e264f3fSAmit Kumar Mahapatra via Alsa-devel mcspi_dma = &mcspi->dma_channels[spi_get_chipselect(spi, 0)]; 597d7b4394eSShubhrajyoti D 598d7b4394eSShubhrajyoti D if (cs->word_len <= 8) { 599d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_1_BYTE; 600d7b4394eSShubhrajyoti D es = 1; 601d7b4394eSShubhrajyoti D } else if (cs->word_len <= 16) { 602d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_2_BYTES; 603d7b4394eSShubhrajyoti D es = 2; 604d7b4394eSShubhrajyoti D } else { 605d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_4_BYTES; 606d7b4394eSShubhrajyoti D es = 4; 607d7b4394eSShubhrajyoti D } 608d7b4394eSShubhrajyoti D 609d33f473dSIllia Smyrnov count = xfer->len; 610d33f473dSIllia Smyrnov 611d7b4394eSShubhrajyoti D memset(&cfg, 0, sizeof(cfg)); 612d7b4394eSShubhrajyoti D cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; 613d7b4394eSShubhrajyoti D cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; 614d7b4394eSShubhrajyoti D cfg.src_addr_width = width; 615d7b4394eSShubhrajyoti D cfg.dst_addr_width = width; 616baf8b9f8SVignesh R cfg.src_maxburst = 1; 617baf8b9f8SVignesh R cfg.dst_maxburst = 1; 618d7b4394eSShubhrajyoti D 619d7b4394eSShubhrajyoti D rx = xfer->rx_buf; 620d7b4394eSShubhrajyoti D tx = xfer->tx_buf; 621d7b4394eSShubhrajyoti D 622ee0f793cSYang Yingliang mcspi->target_aborted = false; 62389e8b9cbSVignesh R reinit_completion(&mcspi_dma->dma_tx_completion); 62489e8b9cbSVignesh R reinit_completion(&mcspi_dma->dma_rx_completion); 62589e8b9cbSVignesh R reinit_completion(&mcspi->txdone); 62689e8b9cbSVignesh R if (tx) { 627ee0f793cSYang Yingliang /* Enable EOW IRQ to know end of tx in target mode */ 628ee0f793cSYang Yingliang if (spi_controller_is_target(spi->controller)) 629ee0f793cSYang Yingliang mcspi_write_reg(spi->controller, 63089e8b9cbSVignesh R OMAP2_MCSPI_IRQENABLE, 63189e8b9cbSVignesh R OMAP2_MCSPI_IRQSTATUS_EOW); 632d7b4394eSShubhrajyoti D omap2_mcspi_tx_dma(spi, xfer, cfg); 63389e8b9cbSVignesh R } 634d7b4394eSShubhrajyoti D 635d7b4394eSShubhrajyoti D if (rx != NULL) 636e47a682aSShubhrajyoti D count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); 637d7b4394eSShubhrajyoti D 638e47a682aSShubhrajyoti D if (tx != NULL) { 63989e8b9cbSVignesh R int ret; 64089e8b9cbSVignesh R 64189e8b9cbSVignesh R ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion); 642ee0f793cSYang Yingliang if (ret || mcspi->target_aborted) { 64389e8b9cbSVignesh R dmaengine_terminate_sync(mcspi_dma->dma_tx); 64489e8b9cbSVignesh R omap2_mcspi_set_dma_req(spi, 0, 0); 64589e8b9cbSVignesh R return 0; 64689e8b9cbSVignesh R } 64789e8b9cbSVignesh R 648ee0f793cSYang Yingliang if (spi_controller_is_target(mcspi->ctlr)) { 64989e8b9cbSVignesh R ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone); 650ee0f793cSYang Yingliang if (ret || mcspi->target_aborted) 65189e8b9cbSVignesh R return 0; 65289e8b9cbSVignesh R } 653e47a682aSShubhrajyoti D 654d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) { 655d33f473dSIllia Smyrnov irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; 656d33f473dSIllia Smyrnov 657d33f473dSIllia Smyrnov if (mcspi_wait_for_reg_bit(irqstat_reg, 658d33f473dSIllia Smyrnov OMAP2_MCSPI_IRQSTATUS_EOW) < 0) 659d33f473dSIllia Smyrnov dev_err(&spi->dev, "EOW timed out\n"); 660d33f473dSIllia Smyrnov 661ee0f793cSYang Yingliang mcspi_write_reg(mcspi->ctlr, OMAP2_MCSPI_IRQSTATUS, 662d33f473dSIllia Smyrnov OMAP2_MCSPI_IRQSTATUS_EOW); 663d33f473dSIllia Smyrnov } 664d33f473dSIllia Smyrnov 665e47a682aSShubhrajyoti D /* for TX_ONLY mode, be sure all words have shifted out */ 666e47a682aSShubhrajyoti D if (rx == NULL) { 667d33f473dSIllia Smyrnov chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; 668d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) { 669d33f473dSIllia Smyrnov wait_res = mcspi_wait_for_reg_bit(chstat_reg, 670d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_TXFFE); 671d33f473dSIllia Smyrnov if (wait_res < 0) 672d33f473dSIllia Smyrnov dev_err(&spi->dev, "TXFFE timed out\n"); 673d33f473dSIllia Smyrnov } else { 674d33f473dSIllia Smyrnov wait_res = mcspi_wait_for_reg_bit(chstat_reg, 675d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_TXS); 676d33f473dSIllia Smyrnov if (wait_res < 0) 677e47a682aSShubhrajyoti D dev_err(&spi->dev, "TXS timed out\n"); 678d33f473dSIllia Smyrnov } 679d33f473dSIllia Smyrnov if (wait_res >= 0 && 680d33f473dSIllia Smyrnov (mcspi_wait_for_reg_bit(chstat_reg, 681d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_EOT) < 0)) 682e47a682aSShubhrajyoti D dev_err(&spi->dev, "EOT timed out\n"); 683e47a682aSShubhrajyoti D } 684e47a682aSShubhrajyoti D } 685ca632f55SGrant Likely return count; 686ca632f55SGrant Likely } 687ca632f55SGrant Likely 688ca632f55SGrant Likely static unsigned 689ca632f55SGrant Likely omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) 690ca632f55SGrant Likely { 691ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 692ca632f55SGrant Likely unsigned int count, c; 693ca632f55SGrant Likely u32 l; 694ca632f55SGrant Likely void __iomem *base = cs->base; 695ca632f55SGrant Likely void __iomem *tx_reg; 696ca632f55SGrant Likely void __iomem *rx_reg; 697ca632f55SGrant Likely void __iomem *chstat_reg; 698ca632f55SGrant Likely int word_len; 699ca632f55SGrant Likely 700ca632f55SGrant Likely count = xfer->len; 701ca632f55SGrant Likely c = count; 702ca632f55SGrant Likely word_len = cs->word_len; 703ca632f55SGrant Likely 704ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 705ca632f55SGrant Likely 706ca632f55SGrant Likely /* We store the pre-calculated register addresses on stack to speed 707ca632f55SGrant Likely * up the transfer loop. */ 708ca632f55SGrant Likely tx_reg = base + OMAP2_MCSPI_TX0; 709ca632f55SGrant Likely rx_reg = base + OMAP2_MCSPI_RX0; 710ca632f55SGrant Likely chstat_reg = base + OMAP2_MCSPI_CHSTAT0; 711ca632f55SGrant Likely 712ca632f55SGrant Likely if (c < (word_len>>3)) 713ca632f55SGrant Likely return 0; 714ca632f55SGrant Likely 715ca632f55SGrant Likely if (word_len <= 8) { 716ca632f55SGrant Likely u8 *rx; 717ca632f55SGrant Likely const u8 *tx; 718ca632f55SGrant Likely 719ca632f55SGrant Likely rx = xfer->rx_buf; 720ca632f55SGrant Likely tx = xfer->tx_buf; 721ca632f55SGrant Likely 722ca632f55SGrant Likely do { 723ca632f55SGrant Likely c -= 1; 724ca632f55SGrant Likely if (tx != NULL) { 725ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 726ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 727ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 728ca632f55SGrant Likely goto out; 729ca632f55SGrant Likely } 730ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %02x\n", 731ca632f55SGrant Likely word_len, *tx); 73221b2ce5eSVictor Kamensky writel_relaxed(*tx++, tx_reg); 733ca632f55SGrant Likely } 734ca632f55SGrant Likely if (rx != NULL) { 735ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 736ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 737ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 738ca632f55SGrant Likely goto out; 739ca632f55SGrant Likely } 740ca632f55SGrant Likely 741ca632f55SGrant Likely if (c == 1 && tx == NULL && 742ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 743ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 74421b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 745ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %02x\n", 746ca632f55SGrant Likely word_len, *(rx - 1)); 747ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 748ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 749ca632f55SGrant Likely dev_err(&spi->dev, 750ca632f55SGrant Likely "RXS timed out\n"); 751ca632f55SGrant Likely goto out; 752ca632f55SGrant Likely } 753ca632f55SGrant Likely c = 0; 754ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 755ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 756ca632f55SGrant Likely } 757ca632f55SGrant Likely 75821b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 759ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %02x\n", 760ca632f55SGrant Likely word_len, *(rx - 1)); 761ca632f55SGrant Likely } 7622cd757e6SAndrea Zanotti /* Add word delay between each word */ 7632cd757e6SAndrea Zanotti spi_delay_exec(&xfer->word_delay, xfer); 764ca632f55SGrant Likely } while (c); 765ca632f55SGrant Likely } else if (word_len <= 16) { 766ca632f55SGrant Likely u16 *rx; 767ca632f55SGrant Likely const u16 *tx; 768ca632f55SGrant Likely 769ca632f55SGrant Likely rx = xfer->rx_buf; 770ca632f55SGrant Likely tx = xfer->tx_buf; 771ca632f55SGrant Likely do { 772ca632f55SGrant Likely c -= 2; 773ca632f55SGrant Likely if (tx != NULL) { 774ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 775ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 776ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 777ca632f55SGrant Likely goto out; 778ca632f55SGrant Likely } 779ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %04x\n", 780ca632f55SGrant Likely word_len, *tx); 78121b2ce5eSVictor Kamensky writel_relaxed(*tx++, tx_reg); 782ca632f55SGrant Likely } 783ca632f55SGrant Likely if (rx != NULL) { 784ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 785ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 786ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 787ca632f55SGrant Likely goto out; 788ca632f55SGrant Likely } 789ca632f55SGrant Likely 790ca632f55SGrant Likely if (c == 2 && tx == NULL && 791ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 792ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 79321b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 794ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %04x\n", 795ca632f55SGrant Likely word_len, *(rx - 1)); 796ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 797ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 798ca632f55SGrant Likely dev_err(&spi->dev, 799ca632f55SGrant Likely "RXS timed out\n"); 800ca632f55SGrant Likely goto out; 801ca632f55SGrant Likely } 802ca632f55SGrant Likely c = 0; 803ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 804ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 805ca632f55SGrant Likely } 806ca632f55SGrant Likely 80721b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 808ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %04x\n", 809ca632f55SGrant Likely word_len, *(rx - 1)); 810ca632f55SGrant Likely } 8112cd757e6SAndrea Zanotti /* Add word delay between each word */ 8122cd757e6SAndrea Zanotti spi_delay_exec(&xfer->word_delay, xfer); 813ca632f55SGrant Likely } while (c >= 2); 814ca632f55SGrant Likely } else if (word_len <= 32) { 815ca632f55SGrant Likely u32 *rx; 816ca632f55SGrant Likely const u32 *tx; 817ca632f55SGrant Likely 818ca632f55SGrant Likely rx = xfer->rx_buf; 819ca632f55SGrant Likely tx = xfer->tx_buf; 820ca632f55SGrant Likely do { 821ca632f55SGrant Likely c -= 4; 822ca632f55SGrant Likely if (tx != NULL) { 823ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 824ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 825ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 826ca632f55SGrant Likely goto out; 827ca632f55SGrant Likely } 828ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %08x\n", 829ca632f55SGrant Likely word_len, *tx); 83021b2ce5eSVictor Kamensky writel_relaxed(*tx++, tx_reg); 831ca632f55SGrant Likely } 832ca632f55SGrant Likely if (rx != NULL) { 833ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 834ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 835ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 836ca632f55SGrant Likely goto out; 837ca632f55SGrant Likely } 838ca632f55SGrant Likely 839ca632f55SGrant Likely if (c == 4 && tx == NULL && 840ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 841ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 84221b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 843ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %08x\n", 844ca632f55SGrant Likely word_len, *(rx - 1)); 845ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 846ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 847ca632f55SGrant Likely dev_err(&spi->dev, 848ca632f55SGrant Likely "RXS timed out\n"); 849ca632f55SGrant Likely goto out; 850ca632f55SGrant Likely } 851ca632f55SGrant Likely c = 0; 852ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 853ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 854ca632f55SGrant Likely } 855ca632f55SGrant Likely 85621b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 857ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %08x\n", 858ca632f55SGrant Likely word_len, *(rx - 1)); 859ca632f55SGrant Likely } 8602cd757e6SAndrea Zanotti /* Add word delay between each word */ 8612cd757e6SAndrea Zanotti spi_delay_exec(&xfer->word_delay, xfer); 862ca632f55SGrant Likely } while (c >= 4); 863ca632f55SGrant Likely } 864ca632f55SGrant Likely 865ca632f55SGrant Likely /* for TX_ONLY mode, be sure all words have shifted out */ 866ca632f55SGrant Likely if (xfer->rx_buf == NULL) { 867ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 868ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 869ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 870ca632f55SGrant Likely } else if (mcspi_wait_for_reg_bit(chstat_reg, 871ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_EOT) < 0) 872ca632f55SGrant Likely dev_err(&spi->dev, "EOT timed out\n"); 873ca632f55SGrant Likely 874ca632f55SGrant Likely /* disable chan to purge rx datas received in TX_ONLY transfer, 875ca632f55SGrant Likely * otherwise these rx datas will affect the direct following 876ca632f55SGrant Likely * RX_ONLY transfer. 877ca632f55SGrant Likely */ 878ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 879ca632f55SGrant Likely } 880ca632f55SGrant Likely out: 881ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 882ca632f55SGrant Likely return count - c; 883ca632f55SGrant Likely } 884ca632f55SGrant Likely 885*2d9f4877SVaishnav Achath static u32 omap2_mcspi_calc_divisor(u32 speed_hz, u32 ref_clk_hz) 886ca632f55SGrant Likely { 887ca632f55SGrant Likely u32 div; 888ca632f55SGrant Likely 889ca632f55SGrant Likely for (div = 0; div < 15; div++) 890*2d9f4877SVaishnav Achath if (speed_hz >= (ref_clk_hz >> div)) 891ca632f55SGrant Likely return div; 892ca632f55SGrant Likely 893ca632f55SGrant Likely return 15; 894ca632f55SGrant Likely } 895ca632f55SGrant Likely 896ca632f55SGrant Likely /* called only when no transfer is active to this device */ 897ca632f55SGrant Likely static int omap2_mcspi_setup_transfer(struct spi_device *spi, 898ca632f55SGrant Likely struct spi_transfer *t) 899ca632f55SGrant Likely { 900ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 901ca632f55SGrant Likely struct omap2_mcspi *mcspi; 902*2d9f4877SVaishnav Achath u32 ref_clk_hz, l = 0, clkd = 0, div, extclk = 0, clkg = 0; 903ca632f55SGrant Likely u8 word_len = spi->bits_per_word; 904ca632f55SGrant Likely u32 speed_hz = spi->max_speed_hz; 905ca632f55SGrant Likely 906ee0f793cSYang Yingliang mcspi = spi_controller_get_devdata(spi->controller); 907ca632f55SGrant Likely 908ca632f55SGrant Likely if (t != NULL && t->bits_per_word) 909ca632f55SGrant Likely word_len = t->bits_per_word; 910ca632f55SGrant Likely 911ca632f55SGrant Likely cs->word_len = word_len; 912ca632f55SGrant Likely 913ca632f55SGrant Likely if (t && t->speed_hz) 914ca632f55SGrant Likely speed_hz = t->speed_hz; 915ca632f55SGrant Likely 916*2d9f4877SVaishnav Achath ref_clk_hz = mcspi->ref_clk_hz; 917*2d9f4877SVaishnav Achath speed_hz = min_t(u32, speed_hz, ref_clk_hz); 918*2d9f4877SVaishnav Achath if (speed_hz < (ref_clk_hz / OMAP2_MCSPI_MAX_DIVIDER)) { 919*2d9f4877SVaishnav Achath clkd = omap2_mcspi_calc_divisor(speed_hz, ref_clk_hz); 920*2d9f4877SVaishnav Achath speed_hz = ref_clk_hz >> clkd; 921faee9b05SStefan Sørensen clkg = 0; 922faee9b05SStefan Sørensen } else { 923*2d9f4877SVaishnav Achath div = (ref_clk_hz + speed_hz - 1) / speed_hz; 924*2d9f4877SVaishnav Achath speed_hz = ref_clk_hz / div; 925faee9b05SStefan Sørensen clkd = (div - 1) & 0xf; 926faee9b05SStefan Sørensen extclk = (div - 1) >> 4; 927faee9b05SStefan Sørensen clkg = OMAP2_MCSPI_CHCONF_CLKG; 928faee9b05SStefan Sørensen } 929ca632f55SGrant Likely 930ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 931ca632f55SGrant Likely 932ee0f793cSYang Yingliang /* standard 4-wire host mode: SCK, MOSI/out, MISO/in, nCS 933ca632f55SGrant Likely * REVISIT: this controller could support SPI_3WIRE mode. 934ca632f55SGrant Likely */ 9352cd45179SDaniel Mack if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) { 9360384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_IS; 9370384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_DPE1; 938ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_DPE0; 9390384e90bSDaniel Mack } else { 9400384e90bSDaniel Mack l |= OMAP2_MCSPI_CHCONF_IS; 9410384e90bSDaniel Mack l |= OMAP2_MCSPI_CHCONF_DPE1; 9420384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_DPE0; 9430384e90bSDaniel Mack } 944ca632f55SGrant Likely 945ca632f55SGrant Likely /* wordlength */ 946ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_WL_MASK; 947ca632f55SGrant Likely l |= (word_len - 1) << 7; 948ca632f55SGrant Likely 949ca632f55SGrant Likely /* set chipselect polarity; manage with FORCE */ 950ca632f55SGrant Likely if (!(spi->mode & SPI_CS_HIGH)) 951ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_EPOL; /* active-low; normal */ 952ca632f55SGrant Likely else 953ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_EPOL; 954ca632f55SGrant Likely 955ca632f55SGrant Likely /* set clock divisor */ 956ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK; 957faee9b05SStefan Sørensen l |= clkd << 2; 958faee9b05SStefan Sørensen 959faee9b05SStefan Sørensen /* set clock granularity */ 960faee9b05SStefan Sørensen l &= ~OMAP2_MCSPI_CHCONF_CLKG; 961faee9b05SStefan Sørensen l |= clkg; 962faee9b05SStefan Sørensen if (clkg) { 963faee9b05SStefan Sørensen cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK; 964faee9b05SStefan Sørensen cs->chctrl0 |= extclk << 8; 965faee9b05SStefan Sørensen mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); 966faee9b05SStefan Sørensen } 967ca632f55SGrant Likely 968ca632f55SGrant Likely /* set SPI mode 0..3 */ 969ca632f55SGrant Likely if (spi->mode & SPI_CPOL) 970ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_POL; 971ca632f55SGrant Likely else 972ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_POL; 973ca632f55SGrant Likely if (spi->mode & SPI_CPHA) 974ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_PHA; 975ca632f55SGrant Likely else 976ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_PHA; 977ca632f55SGrant Likely 978ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 979ca632f55SGrant Likely 98097ca0d6cSMark A. Greer cs->mode = spi->mode; 98197ca0d6cSMark A. Greer 982ca632f55SGrant Likely dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", 983faee9b05SStefan Sørensen speed_hz, 984ca632f55SGrant Likely (spi->mode & SPI_CPHA) ? "trailing" : "leading", 985ca632f55SGrant Likely (spi->mode & SPI_CPOL) ? "inverted" : "normal"); 986ca632f55SGrant Likely 987ca632f55SGrant Likely return 0; 988ca632f55SGrant Likely } 989ca632f55SGrant Likely 990ddc5cdf1STony Lindgren /* 991ddc5cdf1STony Lindgren * Note that we currently allow DMA only if we get a channel 992ddc5cdf1STony Lindgren * for both rx and tx. Otherwise we'll do PIO for both rx and tx. 993ddc5cdf1STony Lindgren */ 99432f2fc5dSVignesh Raghavendra static int omap2_mcspi_request_dma(struct omap2_mcspi *mcspi, 99532f2fc5dSVignesh Raghavendra struct omap2_mcspi_dma *mcspi_dma) 996ca632f55SGrant Likely { 997b085c612SPeter Ujfalusi int ret = 0; 998ca632f55SGrant Likely 99932f2fc5dSVignesh Raghavendra mcspi_dma->dma_rx = dma_request_chan(mcspi->dev, 100074f3aaadSMatt Porter mcspi_dma->dma_rx_ch_name); 1001b085c612SPeter Ujfalusi if (IS_ERR(mcspi_dma->dma_rx)) { 1002b085c612SPeter Ujfalusi ret = PTR_ERR(mcspi_dma->dma_rx); 100353741ed8SRussell King mcspi_dma->dma_rx = NULL; 1004ddc5cdf1STony Lindgren goto no_dma; 100553741ed8SRussell King } 1006ca632f55SGrant Likely 100732f2fc5dSVignesh Raghavendra mcspi_dma->dma_tx = dma_request_chan(mcspi->dev, 1008b085c612SPeter Ujfalusi mcspi_dma->dma_tx_ch_name); 1009b085c612SPeter Ujfalusi if (IS_ERR(mcspi_dma->dma_tx)) { 1010b085c612SPeter Ujfalusi ret = PTR_ERR(mcspi_dma->dma_tx); 1011b085c612SPeter Ujfalusi mcspi_dma->dma_tx = NULL; 1012b085c612SPeter Ujfalusi dma_release_channel(mcspi_dma->dma_rx); 1013b085c612SPeter Ujfalusi mcspi_dma->dma_rx = NULL; 1014b085c612SPeter Ujfalusi } 1015ddc5cdf1STony Lindgren 101632f2fc5dSVignesh Raghavendra init_completion(&mcspi_dma->dma_rx_completion); 101732f2fc5dSVignesh Raghavendra init_completion(&mcspi_dma->dma_tx_completion); 101832f2fc5dSVignesh Raghavendra 1019ddc5cdf1STony Lindgren no_dma: 1020b085c612SPeter Ujfalusi return ret; 1021ca632f55SGrant Likely } 1022ca632f55SGrant Likely 1023ee0f793cSYang Yingliang static void omap2_mcspi_release_dma(struct spi_controller *ctlr) 102432f2fc5dSVignesh Raghavendra { 1025ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 102632f2fc5dSVignesh Raghavendra struct omap2_mcspi_dma *mcspi_dma; 102732f2fc5dSVignesh Raghavendra int i; 102832f2fc5dSVignesh Raghavendra 1029ee0f793cSYang Yingliang for (i = 0; i < ctlr->num_chipselect; i++) { 103032f2fc5dSVignesh Raghavendra mcspi_dma = &mcspi->dma_channels[i]; 103132f2fc5dSVignesh Raghavendra 103232f2fc5dSVignesh Raghavendra if (mcspi_dma->dma_rx) { 103332f2fc5dSVignesh Raghavendra dma_release_channel(mcspi_dma->dma_rx); 103432f2fc5dSVignesh Raghavendra mcspi_dma->dma_rx = NULL; 103532f2fc5dSVignesh Raghavendra } 103632f2fc5dSVignesh Raghavendra if (mcspi_dma->dma_tx) { 103732f2fc5dSVignesh Raghavendra dma_release_channel(mcspi_dma->dma_tx); 103832f2fc5dSVignesh Raghavendra mcspi_dma->dma_tx = NULL; 103932f2fc5dSVignesh Raghavendra } 104032f2fc5dSVignesh Raghavendra } 104132f2fc5dSVignesh Raghavendra } 104232f2fc5dSVignesh Raghavendra 10432ec6f20bSLukas Wunner static void omap2_mcspi_cleanup(struct spi_device *spi) 10442ec6f20bSLukas Wunner { 10452ec6f20bSLukas Wunner struct omap2_mcspi_cs *cs; 10462ec6f20bSLukas Wunner 10472ec6f20bSLukas Wunner if (spi->controller_state) { 10482ec6f20bSLukas Wunner /* Unlink controller state from context save list */ 10492ec6f20bSLukas Wunner cs = spi->controller_state; 10502ec6f20bSLukas Wunner list_del(&cs->node); 10512ec6f20bSLukas Wunner 10522ec6f20bSLukas Wunner kfree(cs); 10532ec6f20bSLukas Wunner } 10542ec6f20bSLukas Wunner } 10552ec6f20bSLukas Wunner 1056ca632f55SGrant Likely static int omap2_mcspi_setup(struct spi_device *spi) 1057ca632f55SGrant Likely { 10582ec6f20bSLukas Wunner bool initial_setup = false; 1059ca632f55SGrant Likely int ret; 1060ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller); 10611bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1062ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 1063ca632f55SGrant Likely 1064ca632f55SGrant Likely if (!cs) { 10658267dc6dSZhiqi Song cs = kzalloc(sizeof(*cs), GFP_KERNEL); 1066ca632f55SGrant Likely if (!cs) 1067ca632f55SGrant Likely return -ENOMEM; 10689e264f3fSAmit Kumar Mahapatra via Alsa-devel cs->base = mcspi->base + spi_get_chipselect(spi, 0) * 0x14; 10699e264f3fSAmit Kumar Mahapatra via Alsa-devel cs->phys = mcspi->phys + spi_get_chipselect(spi, 0) * 0x14; 107097ca0d6cSMark A. Greer cs->mode = 0; 1071ca632f55SGrant Likely cs->chconf0 = 0; 1072faee9b05SStefan Sørensen cs->chctrl0 = 0; 1073ca632f55SGrant Likely spi->controller_state = cs; 1074ca632f55SGrant Likely /* Link this to context save list */ 10751bd897f8SBenoit Cousson list_add_tail(&cs->node, &ctx->cs); 10762ec6f20bSLukas Wunner initial_setup = true; 10772f538c01SMichael Welling } 10782f538c01SMichael Welling 107940b6a137SMinghao Chi ret = pm_runtime_resume_and_get(mcspi->dev); 10805a686b2cSTony Lindgren if (ret < 0) { 10812ec6f20bSLukas Wunner if (initial_setup) 10822ec6f20bSLukas Wunner omap2_mcspi_cleanup(spi); 10835a686b2cSTony Lindgren 1084ca632f55SGrant Likely return ret; 10855a686b2cSTony Lindgren } 1086ca632f55SGrant Likely 1087ca632f55SGrant Likely ret = omap2_mcspi_setup_transfer(spi, NULL); 10882ec6f20bSLukas Wunner if (ret && initial_setup) 10892ec6f20bSLukas Wunner omap2_mcspi_cleanup(spi); 10902ec6f20bSLukas Wunner 1091034d3dc9SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 1092034d3dc9SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 1093ca632f55SGrant Likely 1094ca632f55SGrant Likely return ret; 1095ca632f55SGrant Likely } 1096ca632f55SGrant Likely 109789e8b9cbSVignesh R static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data) 109889e8b9cbSVignesh R { 109989e8b9cbSVignesh R struct omap2_mcspi *mcspi = data; 110089e8b9cbSVignesh R u32 irqstat; 110189e8b9cbSVignesh R 1102ee0f793cSYang Yingliang irqstat = mcspi_read_reg(mcspi->ctlr, OMAP2_MCSPI_IRQSTATUS); 110389e8b9cbSVignesh R if (!irqstat) 110489e8b9cbSVignesh R return IRQ_NONE; 110589e8b9cbSVignesh R 1106ee0f793cSYang Yingliang /* Disable IRQ and wakeup target xfer task */ 1107ee0f793cSYang Yingliang mcspi_write_reg(mcspi->ctlr, OMAP2_MCSPI_IRQENABLE, 0); 110889e8b9cbSVignesh R if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW) 110989e8b9cbSVignesh R complete(&mcspi->txdone); 111089e8b9cbSVignesh R 111189e8b9cbSVignesh R return IRQ_HANDLED; 111289e8b9cbSVignesh R } 111389e8b9cbSVignesh R 1114ee0f793cSYang Yingliang static int omap2_mcspi_target_abort(struct spi_controller *ctlr) 111589e8b9cbSVignesh R { 1116ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 111789e8b9cbSVignesh R struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels; 111889e8b9cbSVignesh R 1119ee0f793cSYang Yingliang mcspi->target_aborted = true; 112089e8b9cbSVignesh R complete(&mcspi_dma->dma_rx_completion); 112189e8b9cbSVignesh R complete(&mcspi_dma->dma_tx_completion); 112289e8b9cbSVignesh R complete(&mcspi->txdone); 112389e8b9cbSVignesh R 112489e8b9cbSVignesh R return 0; 112589e8b9cbSVignesh R } 112689e8b9cbSVignesh R 1127ee0f793cSYang Yingliang static int omap2_mcspi_transfer_one(struct spi_controller *ctlr, 11280ba1870fSFranklin S Cooper Jr struct spi_device *spi, 11290ba1870fSFranklin S Cooper Jr struct spi_transfer *t) 1130ca632f55SGrant Likely { 1131ca632f55SGrant Likely 1132ca632f55SGrant Likely /* We only enable one channel at a time -- the one whose message is 11335fda88f5SShubhrajyoti D * -- although this controller would gladly 1134ca632f55SGrant Likely * arbitrate among multiple channels. This corresponds to "single 1135ee0f793cSYang Yingliang * channel" host mode. As a side effect, we need to manage the 1136ca632f55SGrant Likely * chipselect with the FORCE bit ... CS != channel enable. 1137ca632f55SGrant Likely */ 11385fda88f5SShubhrajyoti D 11390ba1870fSFranklin S Cooper Jr struct omap2_mcspi *mcspi; 1140ddc5cdf1STony Lindgren struct omap2_mcspi_dma *mcspi_dma; 1141ca632f55SGrant Likely struct omap2_mcspi_cs *cs; 1142ca632f55SGrant Likely struct omap2_mcspi_device_config *cd; 1143ca632f55SGrant Likely int par_override = 0; 1144ca632f55SGrant Likely int status = 0; 1145ca632f55SGrant Likely u32 chconf; 1146ca632f55SGrant Likely 1147ee0f793cSYang Yingliang mcspi = spi_controller_get_devdata(ctlr); 11489e264f3fSAmit Kumar Mahapatra via Alsa-devel mcspi_dma = mcspi->dma_channels + spi_get_chipselect(spi, 0); 1149ca632f55SGrant Likely cs = spi->controller_state; 1150ca632f55SGrant Likely cd = spi->controller_data; 1151ca632f55SGrant Likely 115297ca0d6cSMark A. Greer /* 1153ee0f793cSYang Yingliang * The target driver could have changed spi->mode in which case 115497ca0d6cSMark A. Greer * it will be different from cs->mode (the current hardware setup). 115597ca0d6cSMark A. Greer * If so, set par_override (even though its not a parity issue) so 115697ca0d6cSMark A. Greer * omap2_mcspi_setup_transfer will be called to configure the hardware 115797ca0d6cSMark A. Greer * with the correct mode on the first iteration of the loop below. 115897ca0d6cSMark A. Greer */ 115997ca0d6cSMark A. Greer if (spi->mode != cs->mode) 116097ca0d6cSMark A. Greer par_override = 1; 116197ca0d6cSMark A. Greer 1162d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 0); 1163b28cb941SMichael Welling 11649e264f3fSAmit Kumar Mahapatra via Alsa-devel if (spi_get_csgpiod(spi, 0)) 1165a06b430fSMichael Welling omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH); 1166a06b430fSMichael Welling 11672bd16e3eSStefan Sørensen if (par_override || 11682bd16e3eSStefan Sørensen (t->speed_hz != spi->max_speed_hz) || 11692bd16e3eSStefan Sørensen (t->bits_per_word != spi->bits_per_word)) { 1170ca632f55SGrant Likely par_override = 1; 1171ca632f55SGrant Likely status = omap2_mcspi_setup_transfer(spi, t); 1172ca632f55SGrant Likely if (status < 0) 1173b28cb941SMichael Welling goto out; 11742bd16e3eSStefan Sørensen if (t->speed_hz == spi->max_speed_hz && 11752bd16e3eSStefan Sørensen t->bits_per_word == spi->bits_per_word) 1176ca632f55SGrant Likely par_override = 0; 1177ca632f55SGrant Likely } 11785cbc7ca9SMatthias Brugger if (cd && cd->cs_per_word) { 11795cbc7ca9SMatthias Brugger chconf = mcspi->ctx.modulctrl; 11805cbc7ca9SMatthias Brugger chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; 1181ee0f793cSYang Yingliang mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf); 11825cbc7ca9SMatthias Brugger mcspi->ctx.modulctrl = 11835cbc7ca9SMatthias Brugger mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 11845cbc7ca9SMatthias Brugger } 11855cbc7ca9SMatthias Brugger 1186ca632f55SGrant Likely chconf = mcspi_cached_chconf0(spi); 1187ca632f55SGrant Likely chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; 1188ca632f55SGrant Likely chconf &= ~OMAP2_MCSPI_CHCONF_TURBO; 1189ca632f55SGrant Likely 1190ca632f55SGrant Likely if (t->tx_buf == NULL) 1191ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; 1192ca632f55SGrant Likely else if (t->rx_buf == NULL) 1193ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; 1194ca632f55SGrant Likely 1195ca632f55SGrant Likely if (cd && cd->turbo_mode && t->tx_buf == NULL) { 1196ca632f55SGrant Likely /* Turbo mode is for more than one word */ 1197ca632f55SGrant Likely if (t->len > ((cs->word_len + 7) >> 3)) 1198ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TURBO; 1199ca632f55SGrant Likely } 1200ca632f55SGrant Likely 1201ca632f55SGrant Likely mcspi_write_chconf0(spi, chconf); 1202ca632f55SGrant Likely 1203ca632f55SGrant Likely if (t->len) { 1204ca632f55SGrant Likely unsigned count; 1205ca632f55SGrant Likely 1206d33f473dSIllia Smyrnov if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && 1207ee0f793cSYang Yingliang ctlr->cur_msg_mapped && 1208ee0f793cSYang Yingliang ctlr->can_dma(ctlr, spi, t)) 1209d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 1); 1210d33f473dSIllia Smyrnov 1211d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 1); 1212d33f473dSIllia Smyrnov 1213ca632f55SGrant Likely /* RX_ONLY mode needs dummy data in TX reg */ 1214ca632f55SGrant Likely if (t->tx_buf == NULL) 121521b2ce5eSVictor Kamensky writel_relaxed(0, cs->base 1216ca632f55SGrant Likely + OMAP2_MCSPI_TX0); 1217ca632f55SGrant Likely 1218ddc5cdf1STony Lindgren if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && 1219ee0f793cSYang Yingliang ctlr->cur_msg_mapped && 1220ee0f793cSYang Yingliang ctlr->can_dma(ctlr, spi, t)) 1221ca632f55SGrant Likely count = omap2_mcspi_txrx_dma(spi, t); 1222ca632f55SGrant Likely else 1223ca632f55SGrant Likely count = omap2_mcspi_txrx_pio(spi, t); 1224ca632f55SGrant Likely 1225ca632f55SGrant Likely if (count != t->len) { 1226ca632f55SGrant Likely status = -EIO; 1227b28cb941SMichael Welling goto out; 1228ca632f55SGrant Likely } 1229ca632f55SGrant Likely } 1230ca632f55SGrant Likely 1231d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 0); 1232d33f473dSIllia Smyrnov 1233d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) 1234d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 0); 1235b28cb941SMichael Welling 1236b28cb941SMichael Welling out: 1237ca632f55SGrant Likely /* Restore defaults if they were overriden */ 1238ca632f55SGrant Likely if (par_override) { 1239ca632f55SGrant Likely par_override = 0; 1240ca632f55SGrant Likely status = omap2_mcspi_setup_transfer(spi, NULL); 1241ca632f55SGrant Likely } 1242ca632f55SGrant Likely 12435cbc7ca9SMatthias Brugger if (cd && cd->cs_per_word) { 12445cbc7ca9SMatthias Brugger chconf = mcspi->ctx.modulctrl; 12455cbc7ca9SMatthias Brugger chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE; 1246ee0f793cSYang Yingliang mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, chconf); 12475cbc7ca9SMatthias Brugger mcspi->ctx.modulctrl = 12485cbc7ca9SMatthias Brugger mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 12495cbc7ca9SMatthias Brugger } 12505cbc7ca9SMatthias Brugger 1251ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 1252ca632f55SGrant Likely 12539e264f3fSAmit Kumar Mahapatra via Alsa-devel if (spi_get_csgpiod(spi, 0)) 1254a06b430fSMichael Welling omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH)); 1255a06b430fSMichael Welling 1256d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0 && t) 1257d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 0); 1258ca632f55SGrant Likely 1259b28cb941SMichael Welling return status; 1260ca632f55SGrant Likely } 1261ca632f55SGrant Likely 1262ee0f793cSYang Yingliang static int omap2_mcspi_prepare_message(struct spi_controller *ctlr, 1263468a3208SNeil Armstrong struct spi_message *msg) 1264468a3208SNeil Armstrong { 1265ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 1266468a3208SNeil Armstrong struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1267468a3208SNeil Armstrong struct omap2_mcspi_cs *cs; 1268468a3208SNeil Armstrong 1269468a3208SNeil Armstrong /* Only a single channel can have the FORCE bit enabled 1270468a3208SNeil Armstrong * in its chconf0 register. 1271468a3208SNeil Armstrong * Scan all channels and disable them except the current one. 1272468a3208SNeil Armstrong * A FORCE can remain from a last transfer having cs_change enabled 1273468a3208SNeil Armstrong */ 1274468a3208SNeil Armstrong list_for_each_entry(cs, &ctx->cs, node) { 1275468a3208SNeil Armstrong if (msg->spi->controller_state == cs) 1276468a3208SNeil Armstrong continue; 1277468a3208SNeil Armstrong 1278468a3208SNeil Armstrong if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) { 1279468a3208SNeil Armstrong cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; 1280468a3208SNeil Armstrong writel_relaxed(cs->chconf0, 1281468a3208SNeil Armstrong cs->base + OMAP2_MCSPI_CHCONF0); 1282468a3208SNeil Armstrong readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0); 1283468a3208SNeil Armstrong } 1284468a3208SNeil Armstrong } 1285468a3208SNeil Armstrong 1286468a3208SNeil Armstrong return 0; 1287468a3208SNeil Armstrong } 1288468a3208SNeil Armstrong 1289ee0f793cSYang Yingliang static bool omap2_mcspi_can_dma(struct spi_controller *ctlr, 12900ba1870fSFranklin S Cooper Jr struct spi_device *spi, 12910ba1870fSFranklin S Cooper Jr struct spi_transfer *xfer) 1292ca632f55SGrant Likely { 1293ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller); 129489e8b9cbSVignesh R struct omap2_mcspi_dma *mcspi_dma = 12959e264f3fSAmit Kumar Mahapatra via Alsa-devel &mcspi->dma_channels[spi_get_chipselect(spi, 0)]; 129689e8b9cbSVignesh R 129789e8b9cbSVignesh R if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) 129889e8b9cbSVignesh R return false; 129989e8b9cbSVignesh R 1300ee0f793cSYang Yingliang if (spi_controller_is_target(ctlr)) 130189e8b9cbSVignesh R return true; 130289e8b9cbSVignesh R 1303ee0f793cSYang Yingliang ctlr->dma_rx = mcspi_dma->dma_rx; 1304ee0f793cSYang Yingliang ctlr->dma_tx = mcspi_dma->dma_tx; 130532f2fc5dSVignesh Raghavendra 13060ba1870fSFranklin S Cooper Jr return (xfer->len >= DMA_MIN_BYTES); 1307ca632f55SGrant Likely } 1308ca632f55SGrant Likely 1309e4e8276aSVignesh Raghavendra static size_t omap2_mcspi_max_xfer_size(struct spi_device *spi) 1310e4e8276aSVignesh Raghavendra { 1311ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(spi->controller); 1312e4e8276aSVignesh Raghavendra struct omap2_mcspi_dma *mcspi_dma = 13139e264f3fSAmit Kumar Mahapatra via Alsa-devel &mcspi->dma_channels[spi_get_chipselect(spi, 0)]; 1314e4e8276aSVignesh Raghavendra 1315e4e8276aSVignesh Raghavendra if (mcspi->max_xfer_len && mcspi_dma->dma_rx) 1316e4e8276aSVignesh Raghavendra return mcspi->max_xfer_len; 1317e4e8276aSVignesh Raghavendra 1318e4e8276aSVignesh Raghavendra return SIZE_MAX; 1319e4e8276aSVignesh Raghavendra } 1320e4e8276aSVignesh Raghavendra 132189e8b9cbSVignesh R static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi) 1322ca632f55SGrant Likely { 1323ee0f793cSYang Yingliang struct spi_controller *ctlr = mcspi->ctlr; 13241bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1325ca632f55SGrant Likely int ret = 0; 1326ca632f55SGrant Likely 132740b6a137SMinghao Chi ret = pm_runtime_resume_and_get(mcspi->dev); 132840b6a137SMinghao Chi if (ret < 0) 1329ca632f55SGrant Likely return ret; 1330ca632f55SGrant Likely 1331ee0f793cSYang Yingliang mcspi_write_reg(ctlr, OMAP2_MCSPI_WAKEUPENABLE, 133239f8052dSShubhrajyoti D OMAP2_MCSPI_WAKEUPENABLE_WKEN); 133339f8052dSShubhrajyoti D ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; 1334ca632f55SGrant Likely 1335ee0f793cSYang Yingliang omap2_mcspi_set_mode(ctlr); 1336034d3dc9SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 1337034d3dc9SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 1338ca632f55SGrant Likely return 0; 1339ca632f55SGrant Likely } 1340ca632f55SGrant Likely 1341abdc5db3SAlexander Sverdlin static int omap_mcspi_runtime_suspend(struct device *dev) 1342abdc5db3SAlexander Sverdlin { 1343abdc5db3SAlexander Sverdlin int error; 1344abdc5db3SAlexander Sverdlin 1345abdc5db3SAlexander Sverdlin error = pinctrl_pm_select_idle_state(dev); 1346abdc5db3SAlexander Sverdlin if (error) 1347abdc5db3SAlexander Sverdlin dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error); 1348abdc5db3SAlexander Sverdlin 1349abdc5db3SAlexander Sverdlin return 0; 1350abdc5db3SAlexander Sverdlin } 1351abdc5db3SAlexander Sverdlin 135252e9a5bbSTony Lindgren /* 135352e9a5bbSTony Lindgren * When SPI wake up from off-mode, CS is in activate state. If it was in 135452e9a5bbSTony Lindgren * inactive state when driver was suspend, then force it to inactive state at 135552e9a5bbSTony Lindgren * wake up. 135652e9a5bbSTony Lindgren */ 1357ca632f55SGrant Likely static int omap_mcspi_runtime_resume(struct device *dev) 1358ca632f55SGrant Likely { 1359ee0f793cSYang Yingliang struct spi_controller *ctlr = dev_get_drvdata(dev); 1360ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 136152e9a5bbSTony Lindgren struct omap2_mcspi_regs *ctx = &mcspi->ctx; 136252e9a5bbSTony Lindgren struct omap2_mcspi_cs *cs; 1363abdc5db3SAlexander Sverdlin int error; 1364abdc5db3SAlexander Sverdlin 1365abdc5db3SAlexander Sverdlin error = pinctrl_pm_select_default_state(dev); 1366abdc5db3SAlexander Sverdlin if (error) 1367abdc5db3SAlexander Sverdlin dev_warn(dev, "%s: failed to set pins: %i\n", __func__, error); 1368ca632f55SGrant Likely 136952e9a5bbSTony Lindgren /* McSPI: context restore */ 1370ee0f793cSYang Yingliang mcspi_write_reg(ctlr, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); 1371ee0f793cSYang Yingliang mcspi_write_reg(ctlr, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); 137252e9a5bbSTony Lindgren 137352e9a5bbSTony Lindgren list_for_each_entry(cs, &ctx->cs, node) { 137452e9a5bbSTony Lindgren /* 137552e9a5bbSTony Lindgren * We need to toggle CS state for OMAP take this 137652e9a5bbSTony Lindgren * change in account. 137752e9a5bbSTony Lindgren */ 137852e9a5bbSTony Lindgren if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { 137952e9a5bbSTony Lindgren cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; 138052e9a5bbSTony Lindgren writel_relaxed(cs->chconf0, 138152e9a5bbSTony Lindgren cs->base + OMAP2_MCSPI_CHCONF0); 138252e9a5bbSTony Lindgren cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; 138352e9a5bbSTony Lindgren writel_relaxed(cs->chconf0, 138452e9a5bbSTony Lindgren cs->base + OMAP2_MCSPI_CHCONF0); 138552e9a5bbSTony Lindgren } else { 138652e9a5bbSTony Lindgren writel_relaxed(cs->chconf0, 138752e9a5bbSTony Lindgren cs->base + OMAP2_MCSPI_CHCONF0); 138852e9a5bbSTony Lindgren } 138952e9a5bbSTony Lindgren } 1390ca632f55SGrant Likely 1391ca632f55SGrant Likely return 0; 1392ca632f55SGrant Likely } 1393ca632f55SGrant Likely 1394d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap2_pdata = { 1395d5a80031SBenoit Cousson .regs_offset = 0, 1396d5a80031SBenoit Cousson }; 1397d5a80031SBenoit Cousson 1398d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap4_pdata = { 1399d5a80031SBenoit Cousson .regs_offset = OMAP4_MCSPI_REG_OFFSET, 1400d5a80031SBenoit Cousson }; 1401d5a80031SBenoit Cousson 1402e4e8276aSVignesh Raghavendra static struct omap2_mcspi_platform_config am654_pdata = { 1403e4e8276aSVignesh Raghavendra .regs_offset = OMAP4_MCSPI_REG_OFFSET, 1404e4e8276aSVignesh Raghavendra .max_xfer_len = SZ_4K - 1, 1405e4e8276aSVignesh Raghavendra }; 1406e4e8276aSVignesh Raghavendra 1407d5a80031SBenoit Cousson static const struct of_device_id omap_mcspi_of_match[] = { 1408d5a80031SBenoit Cousson { 1409d5a80031SBenoit Cousson .compatible = "ti,omap2-mcspi", 1410d5a80031SBenoit Cousson .data = &omap2_pdata, 1411d5a80031SBenoit Cousson }, 1412d5a80031SBenoit Cousson { 1413d5a80031SBenoit Cousson .compatible = "ti,omap4-mcspi", 1414d5a80031SBenoit Cousson .data = &omap4_pdata, 1415d5a80031SBenoit Cousson }, 1416e4e8276aSVignesh Raghavendra { 1417e4e8276aSVignesh Raghavendra .compatible = "ti,am654-mcspi", 1418e4e8276aSVignesh Raghavendra .data = &am654_pdata, 1419e4e8276aSVignesh Raghavendra }, 1420d5a80031SBenoit Cousson { }, 1421d5a80031SBenoit Cousson }; 1422d5a80031SBenoit Cousson MODULE_DEVICE_TABLE(of, omap_mcspi_of_match); 1423ca632f55SGrant Likely 1424fd4a319bSGrant Likely static int omap2_mcspi_probe(struct platform_device *pdev) 1425ca632f55SGrant Likely { 1426ee0f793cSYang Yingliang struct spi_controller *ctlr; 142783a01e72SUwe Kleine-König const struct omap2_mcspi_platform_config *pdata; 1428ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1429ca632f55SGrant Likely struct resource *r; 1430ca632f55SGrant Likely int status = 0, i; 1431d5a80031SBenoit Cousson u32 regs_offset = 0; 1432d5a80031SBenoit Cousson struct device_node *node = pdev->dev.of_node; 1433d5a80031SBenoit Cousson const struct of_device_id *match; 1434ca632f55SGrant Likely 143589e8b9cbSVignesh R if (of_property_read_bool(node, "spi-slave")) 1436ee0f793cSYang Yingliang ctlr = spi_alloc_target(&pdev->dev, sizeof(*mcspi)); 143789e8b9cbSVignesh R else 1438ee0f793cSYang Yingliang ctlr = spi_alloc_host(&pdev->dev, sizeof(*mcspi)); 1439ee0f793cSYang Yingliang if (!ctlr) 1440ca632f55SGrant Likely return -ENOMEM; 1441ca632f55SGrant Likely 1442ca632f55SGrant Likely /* the spi->mode bits understood by this driver: */ 1443ee0f793cSYang Yingliang ctlr->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; 1444ee0f793cSYang Yingliang ctlr->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 1445ee0f793cSYang Yingliang ctlr->setup = omap2_mcspi_setup; 1446ee0f793cSYang Yingliang ctlr->auto_runtime_pm = true; 1447ee0f793cSYang Yingliang ctlr->prepare_message = omap2_mcspi_prepare_message; 1448ee0f793cSYang Yingliang ctlr->can_dma = omap2_mcspi_can_dma; 1449ee0f793cSYang Yingliang ctlr->transfer_one = omap2_mcspi_transfer_one; 1450ee0f793cSYang Yingliang ctlr->set_cs = omap2_mcspi_set_cs; 1451ee0f793cSYang Yingliang ctlr->cleanup = omap2_mcspi_cleanup; 1452ee0f793cSYang Yingliang ctlr->target_abort = omap2_mcspi_target_abort; 1453ee0f793cSYang Yingliang ctlr->dev.of_node = node; 1454ee0f793cSYang Yingliang ctlr->use_gpio_descriptors = true; 1455d5a80031SBenoit Cousson 1456ee0f793cSYang Yingliang platform_set_drvdata(pdev, ctlr); 14570384e90bSDaniel Mack 1458ee0f793cSYang Yingliang mcspi = spi_controller_get_devdata(ctlr); 1459ee0f793cSYang Yingliang mcspi->ctlr = ctlr; 14600384e90bSDaniel Mack 1461d5a80031SBenoit Cousson match = of_match_device(omap_mcspi_of_match, &pdev->dev); 1462d5a80031SBenoit Cousson if (match) { 1463d5a80031SBenoit Cousson u32 num_cs = 1; /* default number of chipselect */ 1464d5a80031SBenoit Cousson pdata = match->data; 1465d5a80031SBenoit Cousson 1466d5a80031SBenoit Cousson of_property_read_u32(node, "ti,spi-num-cs", &num_cs); 1467ee0f793cSYang Yingliang ctlr->num_chipselect = num_cs; 146803adaa40SRob Herring if (of_property_read_bool(node, "ti,pindir-d0-out-d1-in")) 14692cd45179SDaniel Mack mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; 1470d5a80031SBenoit Cousson } else { 14718074cf06SJingoo Han pdata = dev_get_platdata(&pdev->dev); 1472ee0f793cSYang Yingliang ctlr->num_chipselect = pdata->num_cs; 14730384e90bSDaniel Mack mcspi->pin_dir = pdata->pin_dir; 1474d5a80031SBenoit Cousson } 1475d5a80031SBenoit Cousson regs_offset = pdata->regs_offset; 1476e4e8276aSVignesh Raghavendra if (pdata->max_xfer_len) { 1477e4e8276aSVignesh Raghavendra mcspi->max_xfer_len = pdata->max_xfer_len; 1478ee0f793cSYang Yingliang ctlr->max_transfer_size = omap2_mcspi_max_xfer_size; 1479e4e8276aSVignesh Raghavendra } 1480ca632f55SGrant Likely 14815e726201SYang Li mcspi->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); 1482b0ee5605SThierry Reding if (IS_ERR(mcspi->base)) { 1483b0ee5605SThierry Reding status = PTR_ERR(mcspi->base); 1484ee0f793cSYang Yingliang goto free_ctlr; 1485ca632f55SGrant Likely } 1486af9e53feSVikram N mcspi->phys = r->start + regs_offset; 1487af9e53feSVikram N mcspi->base += regs_offset; 1488ca632f55SGrant Likely 1489ca632f55SGrant Likely mcspi->dev = &pdev->dev; 1490ca632f55SGrant Likely 14911bd897f8SBenoit Cousson INIT_LIST_HEAD(&mcspi->ctx.cs); 1492ca632f55SGrant Likely 1493ee0f793cSYang Yingliang mcspi->dma_channels = devm_kcalloc(&pdev->dev, ctlr->num_chipselect, 1494ca632f55SGrant Likely sizeof(struct omap2_mcspi_dma), 1495ca632f55SGrant Likely GFP_KERNEL); 1496a6f936dbSAxel Lin if (mcspi->dma_channels == NULL) { 1497a6f936dbSAxel Lin status = -ENOMEM; 1498ee0f793cSYang Yingliang goto free_ctlr; 1499a6f936dbSAxel Lin } 1500ca632f55SGrant Likely 1501ee0f793cSYang Yingliang for (i = 0; i < ctlr->num_chipselect; i++) { 1502b085c612SPeter Ujfalusi sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i); 1503b085c612SPeter Ujfalusi sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i); 150432f2fc5dSVignesh Raghavendra 150532f2fc5dSVignesh Raghavendra status = omap2_mcspi_request_dma(mcspi, 150632f2fc5dSVignesh Raghavendra &mcspi->dma_channels[i]); 150732f2fc5dSVignesh Raghavendra if (status == -EPROBE_DEFER) 1508ee0f793cSYang Yingliang goto free_ctlr; 1509ca632f55SGrant Likely } 1510ca632f55SGrant Likely 151189e8b9cbSVignesh R status = platform_get_irq(pdev, 0); 1512142c61a5SZhu Wang if (status < 0) 1513ee0f793cSYang Yingliang goto free_ctlr; 151489e8b9cbSVignesh R init_completion(&mcspi->txdone); 151589e8b9cbSVignesh R status = devm_request_irq(&pdev->dev, status, 151689e8b9cbSVignesh R omap2_mcspi_irq_handler, 0, pdev->name, 151789e8b9cbSVignesh R mcspi); 151889e8b9cbSVignesh R if (status) { 151989e8b9cbSVignesh R dev_err(&pdev->dev, "Cannot request IRQ"); 1520ee0f793cSYang Yingliang goto free_ctlr; 152189e8b9cbSVignesh R } 152289e8b9cbSVignesh R 1523*2d9f4877SVaishnav Achath mcspi->ref_clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); 1524*2d9f4877SVaishnav Achath if (mcspi->ref_clk) 1525*2d9f4877SVaishnav Achath mcspi->ref_clk_hz = clk_get_rate(mcspi->ref_clk); 1526*2d9f4877SVaishnav Achath else 1527*2d9f4877SVaishnav Achath mcspi->ref_clk_hz = OMAP2_MCSPI_MAX_FREQ; 1528*2d9f4877SVaishnav Achath ctlr->max_speed_hz = mcspi->ref_clk_hz; 1529*2d9f4877SVaishnav Achath ctlr->min_speed_hz = mcspi->ref_clk_hz >> 15; 1530*2d9f4877SVaishnav Achath 153127b5284cSShubhrajyoti D pm_runtime_use_autosuspend(&pdev->dev); 153227b5284cSShubhrajyoti D pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); 1533ca632f55SGrant Likely pm_runtime_enable(&pdev->dev); 1534ca632f55SGrant Likely 153589e8b9cbSVignesh R status = omap2_mcspi_controller_setup(mcspi); 1536142e07beSWei Yongjun if (status < 0) 153739f1b565SShubhrajyoti D goto disable_pm; 1538ca632f55SGrant Likely 1539ee0f793cSYang Yingliang status = devm_spi_register_controller(&pdev->dev, ctlr); 1540ca632f55SGrant Likely if (status < 0) 154137a2d84aSShubhrajyoti D goto disable_pm; 1542ca632f55SGrant Likely 1543ca632f55SGrant Likely return status; 1544ca632f55SGrant Likely 154539f1b565SShubhrajyoti D disable_pm: 15460e6f357aSTony Lindgren pm_runtime_dont_use_autosuspend(&pdev->dev); 15470e6f357aSTony Lindgren pm_runtime_put_sync(&pdev->dev); 1548751c925cSShubhrajyoti D pm_runtime_disable(&pdev->dev); 1549ee0f793cSYang Yingliang free_ctlr: 1550ee0f793cSYang Yingliang omap2_mcspi_release_dma(ctlr); 1551ee0f793cSYang Yingliang spi_controller_put(ctlr); 1552ca632f55SGrant Likely return status; 1553ca632f55SGrant Likely } 1554ca632f55SGrant Likely 15550a4192a5SUwe Kleine-König static void omap2_mcspi_remove(struct platform_device *pdev) 1556ca632f55SGrant Likely { 1557ee0f793cSYang Yingliang struct spi_controller *ctlr = platform_get_drvdata(pdev); 1558ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 1559ca632f55SGrant Likely 1560ee0f793cSYang Yingliang omap2_mcspi_release_dma(ctlr); 156132f2fc5dSVignesh Raghavendra 15620e6f357aSTony Lindgren pm_runtime_dont_use_autosuspend(mcspi->dev); 1563a93a2029SShubhrajyoti D pm_runtime_put_sync(mcspi->dev); 1564751c925cSShubhrajyoti D pm_runtime_disable(&pdev->dev); 1565ca632f55SGrant Likely } 1566ca632f55SGrant Likely 1567ca632f55SGrant Likely /* work with hotplug and coldplug */ 1568ca632f55SGrant Likely MODULE_ALIAS("platform:omap2_mcspi"); 1569ca632f55SGrant Likely 157091b9deefSTony Lindgren static int __maybe_unused omap2_mcspi_suspend(struct device *dev) 1571ca632f55SGrant Likely { 1572ee0f793cSYang Yingliang struct spi_controller *ctlr = dev_get_drvdata(dev); 1573ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 157491b9deefSTony Lindgren int error; 157591b9deefSTony Lindgren 157691b9deefSTony Lindgren error = pinctrl_pm_select_sleep_state(dev); 157791b9deefSTony Lindgren if (error) 157891b9deefSTony Lindgren dev_warn(mcspi->dev, "%s: failed to set pins: %i\n", 157991b9deefSTony Lindgren __func__, error); 158091b9deefSTony Lindgren 1581ee0f793cSYang Yingliang error = spi_controller_suspend(ctlr); 158291b9deefSTony Lindgren if (error) 1583ee0f793cSYang Yingliang dev_warn(mcspi->dev, "%s: controller suspend failed: %i\n", 158491b9deefSTony Lindgren __func__, error); 158591b9deefSTony Lindgren 158691b9deefSTony Lindgren return pm_runtime_force_suspend(dev); 1587beca3655SPascal Huerst } 1588beca3655SPascal Huerst 158991b9deefSTony Lindgren static int __maybe_unused omap2_mcspi_resume(struct device *dev) 15905a686b2cSTony Lindgren { 1591ee0f793cSYang Yingliang struct spi_controller *ctlr = dev_get_drvdata(dev); 1592ee0f793cSYang Yingliang struct omap2_mcspi *mcspi = spi_controller_get_devdata(ctlr); 15935a686b2cSTony Lindgren int error; 15945a686b2cSTony Lindgren 1595ee0f793cSYang Yingliang error = spi_controller_resume(ctlr); 159691b9deefSTony Lindgren if (error) 1597ee0f793cSYang Yingliang dev_warn(mcspi->dev, "%s: controller resume failed: %i\n", 159891b9deefSTony Lindgren __func__, error); 159991b9deefSTony Lindgren 160091b9deefSTony Lindgren return pm_runtime_force_resume(dev); 16015a686b2cSTony Lindgren } 16025a686b2cSTony Lindgren 1603ca632f55SGrant Likely static const struct dev_pm_ops omap2_mcspi_pm_ops = { 160491b9deefSTony Lindgren SET_SYSTEM_SLEEP_PM_OPS(omap2_mcspi_suspend, 160591b9deefSTony Lindgren omap2_mcspi_resume) 1606abdc5db3SAlexander Sverdlin .runtime_suspend = omap_mcspi_runtime_suspend, 1607ca632f55SGrant Likely .runtime_resume = omap_mcspi_runtime_resume, 1608ca632f55SGrant Likely }; 1609ca632f55SGrant Likely 1610ca632f55SGrant Likely static struct platform_driver omap2_mcspi_driver = { 1611ca632f55SGrant Likely .driver = { 1612ca632f55SGrant Likely .name = "omap2_mcspi", 1613d5a80031SBenoit Cousson .pm = &omap2_mcspi_pm_ops, 1614d5a80031SBenoit Cousson .of_match_table = omap_mcspi_of_match, 1615ca632f55SGrant Likely }, 16167d6b6d83SFelipe Balbi .probe = omap2_mcspi_probe, 16170a4192a5SUwe Kleine-König .remove_new = omap2_mcspi_remove, 1618ca632f55SGrant Likely }; 1619ca632f55SGrant Likely 16209fdca9dfSFelipe Balbi module_platform_driver(omap2_mcspi_driver); 1621ca632f55SGrant Likely MODULE_LICENSE("GPL"); 1622