1ca632f55SGrant Likely /* 2ca632f55SGrant Likely * OMAP2 McSPI controller driver 3ca632f55SGrant Likely * 4ca632f55SGrant Likely * Copyright (C) 2005, 2006 Nokia Corporation 5ca632f55SGrant Likely * Author: Samuel Ortiz <samuel.ortiz@nokia.com> and 6ca632f55SGrant Likely * Juha Yrj�l� <juha.yrjola@nokia.com> 7ca632f55SGrant Likely * 8ca632f55SGrant Likely * This program is free software; you can redistribute it and/or modify 9ca632f55SGrant Likely * it under the terms of the GNU General Public License as published by 10ca632f55SGrant Likely * the Free Software Foundation; either version 2 of the License, or 11ca632f55SGrant Likely * (at your option) any later version. 12ca632f55SGrant Likely * 13ca632f55SGrant Likely * This program is distributed in the hope that it will be useful, 14ca632f55SGrant Likely * but WITHOUT ANY WARRANTY; without even the implied warranty of 15ca632f55SGrant Likely * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16ca632f55SGrant Likely * GNU General Public License for more details. 17ca632f55SGrant Likely */ 18ca632f55SGrant Likely 19ca632f55SGrant Likely #include <linux/kernel.h> 20ca632f55SGrant Likely #include <linux/interrupt.h> 21ca632f55SGrant Likely #include <linux/module.h> 22ca632f55SGrant Likely #include <linux/device.h> 23ca632f55SGrant Likely #include <linux/delay.h> 24ca632f55SGrant Likely #include <linux/dma-mapping.h> 2553741ed8SRussell King #include <linux/dmaengine.h> 26beca3655SPascal Huerst #include <linux/pinctrl/consumer.h> 27ca632f55SGrant Likely #include <linux/platform_device.h> 28ca632f55SGrant Likely #include <linux/err.h> 29ca632f55SGrant Likely #include <linux/clk.h> 30ca632f55SGrant Likely #include <linux/io.h> 31ca632f55SGrant Likely #include <linux/slab.h> 32ca632f55SGrant Likely #include <linux/pm_runtime.h> 33d5a80031SBenoit Cousson #include <linux/of.h> 34d5a80031SBenoit Cousson #include <linux/of_device.h> 35d33f473dSIllia Smyrnov #include <linux/gcd.h> 3613d515c7SVignesh R #include <linux/iopoll.h> 37ca632f55SGrant Likely 38ca632f55SGrant Likely #include <linux/spi/spi.h> 39bc7f9bbcSMichael Welling #include <linux/gpio.h> 40ca632f55SGrant Likely 412203747cSArnd Bergmann #include <linux/platform_data/spi-omap2-mcspi.h> 42ca632f55SGrant Likely 43ca632f55SGrant Likely #define OMAP2_MCSPI_MAX_FREQ 48000000 44faee9b05SStefan Sørensen #define OMAP2_MCSPI_MAX_DIVIDER 4096 45d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFODEPTH 64 46d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF 4727b5284cSShubhrajyoti D #define SPI_AUTOSUSPEND_TIMEOUT 2000 48ca632f55SGrant Likely 49ca632f55SGrant Likely #define OMAP2_MCSPI_REVISION 0x00 50ca632f55SGrant Likely #define OMAP2_MCSPI_SYSSTATUS 0x14 51ca632f55SGrant Likely #define OMAP2_MCSPI_IRQSTATUS 0x18 52ca632f55SGrant Likely #define OMAP2_MCSPI_IRQENABLE 0x1c 53ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE 0x20 54ca632f55SGrant Likely #define OMAP2_MCSPI_SYST 0x24 55ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL 0x28 56d33f473dSIllia Smyrnov #define OMAP2_MCSPI_XFERLEVEL 0x7c 57ca632f55SGrant Likely 58ca632f55SGrant Likely /* per-channel banks, 0x14 bytes each, first is: */ 59ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF0 0x2c 60ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT0 0x30 61ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL0 0x34 62ca632f55SGrant Likely #define OMAP2_MCSPI_TX0 0x38 63ca632f55SGrant Likely #define OMAP2_MCSPI_RX0 0x3c 64ca632f55SGrant Likely 65ca632f55SGrant Likely /* per-register bitmasks: */ 66d33f473dSIllia Smyrnov #define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17) 67ca632f55SGrant Likely 68ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) 69ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) 70ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_STEST BIT(3) 71ca632f55SGrant Likely 72ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_PHA BIT(0) 73ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_POL BIT(1) 74ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_CLKD_MASK (0x0f << 2) 75ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_EPOL BIT(6) 76ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_WL_MASK (0x1f << 7) 77ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY BIT(12) 78ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY BIT(13) 79ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_MASK (0x03 << 12) 80ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAW BIT(14) 81ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAR BIT(15) 82ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE0 BIT(16) 83ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE1 BIT(17) 84ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_IS BIT(18) 85ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) 86ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) 87d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFET BIT(27) 88d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFER BIT(28) 89faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCONF_CLKG BIT(29) 90ca632f55SGrant Likely 91ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) 92ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) 93ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) 94d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) 95ca632f55SGrant Likely 96ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL_EN BIT(0) 97faee9b05SStefan Sørensen #define OMAP2_MCSPI_CHCTRL_EXTCLK_MASK (0xff << 8) 98ca632f55SGrant Likely 99ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) 100ca632f55SGrant Likely 101ca632f55SGrant Likely /* We have 2 DMA channels per CS, one for RX and one for TX */ 102ca632f55SGrant Likely struct omap2_mcspi_dma { 10353741ed8SRussell King struct dma_chan *dma_tx; 10453741ed8SRussell King struct dma_chan *dma_rx; 105ca632f55SGrant Likely 106ca632f55SGrant Likely struct completion dma_tx_completion; 107ca632f55SGrant Likely struct completion dma_rx_completion; 10874f3aaadSMatt Porter 10974f3aaadSMatt Porter char dma_rx_ch_name[14]; 11074f3aaadSMatt Porter char dma_tx_ch_name[14]; 111ca632f55SGrant Likely }; 112ca632f55SGrant Likely 113ca632f55SGrant Likely /* use PIO for small transfers, avoiding DMA setup/teardown overhead and 114ca632f55SGrant Likely * cache operations; better heuristics consider wordsize and bitrate. 115ca632f55SGrant Likely */ 116ca632f55SGrant Likely #define DMA_MIN_BYTES 160 117ca632f55SGrant Likely 118ca632f55SGrant Likely 1191bd897f8SBenoit Cousson /* 1201bd897f8SBenoit Cousson * Used for context save and restore, structure members to be updated whenever 1211bd897f8SBenoit Cousson * corresponding registers are modified. 1221bd897f8SBenoit Cousson */ 1231bd897f8SBenoit Cousson struct omap2_mcspi_regs { 1241bd897f8SBenoit Cousson u32 modulctrl; 1251bd897f8SBenoit Cousson u32 wakeupenable; 1261bd897f8SBenoit Cousson struct list_head cs; 1271bd897f8SBenoit Cousson }; 1281bd897f8SBenoit Cousson 129ca632f55SGrant Likely struct omap2_mcspi { 130*89e8b9cbSVignesh R struct completion txdone; 131ca632f55SGrant Likely struct spi_master *master; 132ca632f55SGrant Likely /* Virtual base address of the controller */ 133ca632f55SGrant Likely void __iomem *base; 134ca632f55SGrant Likely unsigned long phys; 135ca632f55SGrant Likely /* SPI1 has 4 channels, while SPI2 has 2 */ 136ca632f55SGrant Likely struct omap2_mcspi_dma *dma_channels; 137ca632f55SGrant Likely struct device *dev; 1381bd897f8SBenoit Cousson struct omap2_mcspi_regs ctx; 139d33f473dSIllia Smyrnov int fifo_depth; 140*89e8b9cbSVignesh R bool slave_aborted; 1410384e90bSDaniel Mack unsigned int pin_dir:1; 142ca632f55SGrant Likely }; 143ca632f55SGrant Likely 144ca632f55SGrant Likely struct omap2_mcspi_cs { 145ca632f55SGrant Likely void __iomem *base; 146ca632f55SGrant Likely unsigned long phys; 147ca632f55SGrant Likely int word_len; 14897ca0d6cSMark A. Greer u16 mode; 149ca632f55SGrant Likely struct list_head node; 150ca632f55SGrant Likely /* Context save and restore shadow register */ 151faee9b05SStefan Sørensen u32 chconf0, chctrl0; 152ca632f55SGrant Likely }; 153ca632f55SGrant Likely 154ca632f55SGrant Likely static inline void mcspi_write_reg(struct spi_master *master, 155ca632f55SGrant Likely int idx, u32 val) 156ca632f55SGrant Likely { 157ca632f55SGrant Likely struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 158ca632f55SGrant Likely 15921b2ce5eSVictor Kamensky writel_relaxed(val, mcspi->base + idx); 160ca632f55SGrant Likely } 161ca632f55SGrant Likely 162ca632f55SGrant Likely static inline u32 mcspi_read_reg(struct spi_master *master, int idx) 163ca632f55SGrant Likely { 164ca632f55SGrant Likely struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 165ca632f55SGrant Likely 16621b2ce5eSVictor Kamensky return readl_relaxed(mcspi->base + idx); 167ca632f55SGrant Likely } 168ca632f55SGrant Likely 169ca632f55SGrant Likely static inline void mcspi_write_cs_reg(const struct spi_device *spi, 170ca632f55SGrant Likely int idx, u32 val) 171ca632f55SGrant Likely { 172ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 173ca632f55SGrant Likely 17421b2ce5eSVictor Kamensky writel_relaxed(val, cs->base + idx); 175ca632f55SGrant Likely } 176ca632f55SGrant Likely 177ca632f55SGrant Likely static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx) 178ca632f55SGrant Likely { 179ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 180ca632f55SGrant Likely 18121b2ce5eSVictor Kamensky return readl_relaxed(cs->base + idx); 182ca632f55SGrant Likely } 183ca632f55SGrant Likely 184ca632f55SGrant Likely static inline u32 mcspi_cached_chconf0(const struct spi_device *spi) 185ca632f55SGrant Likely { 186ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 187ca632f55SGrant Likely 188ca632f55SGrant Likely return cs->chconf0; 189ca632f55SGrant Likely } 190ca632f55SGrant Likely 191ca632f55SGrant Likely static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val) 192ca632f55SGrant Likely { 193ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 194ca632f55SGrant Likely 195ca632f55SGrant Likely cs->chconf0 = val; 196ca632f55SGrant Likely mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val); 197ca632f55SGrant Likely mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); 198ca632f55SGrant Likely } 199ca632f55SGrant Likely 20056cd5c15SIllia Smyrnov static inline int mcspi_bytes_per_word(int word_len) 20156cd5c15SIllia Smyrnov { 20256cd5c15SIllia Smyrnov if (word_len <= 8) 20356cd5c15SIllia Smyrnov return 1; 20456cd5c15SIllia Smyrnov else if (word_len <= 16) 20556cd5c15SIllia Smyrnov return 2; 20656cd5c15SIllia Smyrnov else /* word_len <= 32 */ 20756cd5c15SIllia Smyrnov return 4; 20856cd5c15SIllia Smyrnov } 20956cd5c15SIllia Smyrnov 210ca632f55SGrant Likely static void omap2_mcspi_set_dma_req(const struct spi_device *spi, 211ca632f55SGrant Likely int is_read, int enable) 212ca632f55SGrant Likely { 213ca632f55SGrant Likely u32 l, rw; 214ca632f55SGrant Likely 215ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 216ca632f55SGrant Likely 217ca632f55SGrant Likely if (is_read) /* 1 is read, 0 write */ 218ca632f55SGrant Likely rw = OMAP2_MCSPI_CHCONF_DMAR; 219ca632f55SGrant Likely else 220ca632f55SGrant Likely rw = OMAP2_MCSPI_CHCONF_DMAW; 221ca632f55SGrant Likely 222af4e944dSShubhrajyoti D if (enable) 223af4e944dSShubhrajyoti D l |= rw; 224af4e944dSShubhrajyoti D else 225af4e944dSShubhrajyoti D l &= ~rw; 226af4e944dSShubhrajyoti D 227ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 228ca632f55SGrant Likely } 229ca632f55SGrant Likely 230ca632f55SGrant Likely static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) 231ca632f55SGrant Likely { 232faee9b05SStefan Sørensen struct omap2_mcspi_cs *cs = spi->controller_state; 233ca632f55SGrant Likely u32 l; 234ca632f55SGrant Likely 235faee9b05SStefan Sørensen l = cs->chctrl0; 236faee9b05SStefan Sørensen if (enable) 237faee9b05SStefan Sørensen l |= OMAP2_MCSPI_CHCTRL_EN; 238faee9b05SStefan Sørensen else 239faee9b05SStefan Sørensen l &= ~OMAP2_MCSPI_CHCTRL_EN; 240faee9b05SStefan Sørensen cs->chctrl0 = l; 241faee9b05SStefan Sørensen mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); 242ca632f55SGrant Likely /* Flash post-writes */ 243ca632f55SGrant Likely mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); 244ca632f55SGrant Likely } 245ca632f55SGrant Likely 246ddcad7e9SMichael Welling static void omap2_mcspi_set_cs(struct spi_device *spi, bool enable) 247ca632f55SGrant Likely { 2485f74db10SSebastian Reichel struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 249ca632f55SGrant Likely u32 l; 250ca632f55SGrant Likely 2514373f8b6SMichael Welling /* The controller handles the inverted chip selects 2524373f8b6SMichael Welling * using the OMAP2_MCSPI_CHCONF_EPOL bit so revert 2534373f8b6SMichael Welling * the inversion from the core spi_set_cs function. 2544373f8b6SMichael Welling */ 2554373f8b6SMichael Welling if (spi->mode & SPI_CS_HIGH) 2564373f8b6SMichael Welling enable = !enable; 2574373f8b6SMichael Welling 258ddcad7e9SMichael Welling if (spi->controller_state) { 2595f74db10SSebastian Reichel int err = pm_runtime_get_sync(mcspi->dev); 2605f74db10SSebastian Reichel if (err < 0) { 2615a686b2cSTony Lindgren pm_runtime_put_noidle(mcspi->dev); 2625f74db10SSebastian Reichel dev_err(mcspi->dev, "failed to get sync: %d\n", err); 2635f74db10SSebastian Reichel return; 2645f74db10SSebastian Reichel } 2655f74db10SSebastian Reichel 266ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 267ddcad7e9SMichael Welling 268ddcad7e9SMichael Welling if (enable) 269af4e944dSShubhrajyoti D l &= ~OMAP2_MCSPI_CHCONF_FORCE; 270ddcad7e9SMichael Welling else 271ddcad7e9SMichael Welling l |= OMAP2_MCSPI_CHCONF_FORCE; 272af4e944dSShubhrajyoti D 273ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 2745f74db10SSebastian Reichel 2755f74db10SSebastian Reichel pm_runtime_mark_last_busy(mcspi->dev); 2765f74db10SSebastian Reichel pm_runtime_put_autosuspend(mcspi->dev); 277ca632f55SGrant Likely } 278ddcad7e9SMichael Welling } 279ca632f55SGrant Likely 280*89e8b9cbSVignesh R static void omap2_mcspi_set_mode(struct spi_master *master) 281ca632f55SGrant Likely { 2821bd897f8SBenoit Cousson struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 2831bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 284ca632f55SGrant Likely u32 l; 285ca632f55SGrant Likely 2861bd897f8SBenoit Cousson /* 287*89e8b9cbSVignesh R * Choose master or slave mode 288ca632f55SGrant Likely */ 289ca632f55SGrant Likely l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); 290*89e8b9cbSVignesh R l &= ~(OMAP2_MCSPI_MODULCTRL_STEST); 291*89e8b9cbSVignesh R if (spi_controller_is_slave(master)) { 292*89e8b9cbSVignesh R l |= (OMAP2_MCSPI_MODULCTRL_MS); 293*89e8b9cbSVignesh R } else { 294*89e8b9cbSVignesh R l &= ~(OMAP2_MCSPI_MODULCTRL_MS); 295af4e944dSShubhrajyoti D l |= OMAP2_MCSPI_MODULCTRL_SINGLE; 296*89e8b9cbSVignesh R } 297ca632f55SGrant Likely mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); 298ca632f55SGrant Likely 2991bd897f8SBenoit Cousson ctx->modulctrl = l; 300ca632f55SGrant Likely } 301ca632f55SGrant Likely 302d33f473dSIllia Smyrnov static void omap2_mcspi_set_fifo(const struct spi_device *spi, 303d33f473dSIllia Smyrnov struct spi_transfer *t, int enable) 304d33f473dSIllia Smyrnov { 305d33f473dSIllia Smyrnov struct spi_master *master = spi->master; 306d33f473dSIllia Smyrnov struct omap2_mcspi_cs *cs = spi->controller_state; 307d33f473dSIllia Smyrnov struct omap2_mcspi *mcspi; 308d33f473dSIllia Smyrnov unsigned int wcnt; 309b682cffaSVignesh R int max_fifo_depth, bytes_per_word; 310d33f473dSIllia Smyrnov u32 chconf, xferlevel; 311d33f473dSIllia Smyrnov 312d33f473dSIllia Smyrnov mcspi = spi_master_get_devdata(master); 313d33f473dSIllia Smyrnov 314d33f473dSIllia Smyrnov chconf = mcspi_cached_chconf0(spi); 315d33f473dSIllia Smyrnov if (enable) { 316d33f473dSIllia Smyrnov bytes_per_word = mcspi_bytes_per_word(cs->word_len); 317d33f473dSIllia Smyrnov if (t->len % bytes_per_word != 0) 318d33f473dSIllia Smyrnov goto disable_fifo; 319d33f473dSIllia Smyrnov 3205db542edSIllia Smyrnov if (t->rx_buf != NULL && t->tx_buf != NULL) 3215db542edSIllia Smyrnov max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH / 2; 3225db542edSIllia Smyrnov else 3235db542edSIllia Smyrnov max_fifo_depth = OMAP2_MCSPI_MAX_FIFODEPTH; 3245db542edSIllia Smyrnov 325d33f473dSIllia Smyrnov wcnt = t->len / bytes_per_word; 326d33f473dSIllia Smyrnov if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) 327d33f473dSIllia Smyrnov goto disable_fifo; 328d33f473dSIllia Smyrnov 329d33f473dSIllia Smyrnov xferlevel = wcnt << 16; 330d33f473dSIllia Smyrnov if (t->rx_buf != NULL) { 331d33f473dSIllia Smyrnov chconf |= OMAP2_MCSPI_CHCONF_FFER; 332b682cffaSVignesh R xferlevel |= (bytes_per_word - 1) << 8; 3335db542edSIllia Smyrnov } 334b682cffaSVignesh R 3355db542edSIllia Smyrnov if (t->tx_buf != NULL) { 336d33f473dSIllia Smyrnov chconf |= OMAP2_MCSPI_CHCONF_FFET; 337b682cffaSVignesh R xferlevel |= bytes_per_word - 1; 338d33f473dSIllia Smyrnov } 339d33f473dSIllia Smyrnov 340d33f473dSIllia Smyrnov mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel); 341d33f473dSIllia Smyrnov mcspi_write_chconf0(spi, chconf); 342b682cffaSVignesh R mcspi->fifo_depth = max_fifo_depth; 343d33f473dSIllia Smyrnov 344d33f473dSIllia Smyrnov return; 345d33f473dSIllia Smyrnov } 346d33f473dSIllia Smyrnov 347d33f473dSIllia Smyrnov disable_fifo: 348d33f473dSIllia Smyrnov if (t->rx_buf != NULL) 349d33f473dSIllia Smyrnov chconf &= ~OMAP2_MCSPI_CHCONF_FFER; 3503d0763c0SJorge A. Ventura 3513d0763c0SJorge A. Ventura if (t->tx_buf != NULL) 352d33f473dSIllia Smyrnov chconf &= ~OMAP2_MCSPI_CHCONF_FFET; 353d33f473dSIllia Smyrnov 354d33f473dSIllia Smyrnov mcspi_write_chconf0(spi, chconf); 355d33f473dSIllia Smyrnov mcspi->fifo_depth = 0; 356d33f473dSIllia Smyrnov } 357d33f473dSIllia Smyrnov 358ca632f55SGrant Likely static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) 359ca632f55SGrant Likely { 36013d515c7SVignesh R u32 val; 361ca632f55SGrant Likely 36213d515c7SVignesh R return readl_poll_timeout(reg, val, val & bit, 1, MSEC_PER_SEC); 363ca632f55SGrant Likely } 364ca632f55SGrant Likely 365*89e8b9cbSVignesh R static int mcspi_wait_for_completion(struct omap2_mcspi *mcspi, 366*89e8b9cbSVignesh R struct completion *x) 367*89e8b9cbSVignesh R { 368*89e8b9cbSVignesh R if (spi_controller_is_slave(mcspi->master)) { 369*89e8b9cbSVignesh R if (wait_for_completion_interruptible(x) || 370*89e8b9cbSVignesh R mcspi->slave_aborted) 371*89e8b9cbSVignesh R return -EINTR; 372*89e8b9cbSVignesh R } else { 373*89e8b9cbSVignesh R wait_for_completion(x); 374*89e8b9cbSVignesh R } 375*89e8b9cbSVignesh R 376*89e8b9cbSVignesh R return 0; 377*89e8b9cbSVignesh R } 378*89e8b9cbSVignesh R 37953741ed8SRussell King static void omap2_mcspi_rx_callback(void *data) 38053741ed8SRussell King { 38153741ed8SRussell King struct spi_device *spi = data; 38253741ed8SRussell King struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 38353741ed8SRussell King struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 38453741ed8SRussell King 38553741ed8SRussell King /* We must disable the DMA RX request */ 38653741ed8SRussell King omap2_mcspi_set_dma_req(spi, 1, 0); 387830379e0SFelipe Balbi 388830379e0SFelipe Balbi complete(&mcspi_dma->dma_rx_completion); 38953741ed8SRussell King } 39053741ed8SRussell King 39153741ed8SRussell King static void omap2_mcspi_tx_callback(void *data) 39253741ed8SRussell King { 39353741ed8SRussell King struct spi_device *spi = data; 39453741ed8SRussell King struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 39553741ed8SRussell King struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 39653741ed8SRussell King 39753741ed8SRussell King /* We must disable the DMA TX request */ 39853741ed8SRussell King omap2_mcspi_set_dma_req(spi, 0, 0); 399830379e0SFelipe Balbi 400830379e0SFelipe Balbi complete(&mcspi_dma->dma_tx_completion); 40153741ed8SRussell King } 40253741ed8SRussell King 403d7b4394eSShubhrajyoti D static void omap2_mcspi_tx_dma(struct spi_device *spi, 404d7b4394eSShubhrajyoti D struct spi_transfer *xfer, 405d7b4394eSShubhrajyoti D struct dma_slave_config cfg) 406ca632f55SGrant Likely { 407ca632f55SGrant Likely struct omap2_mcspi *mcspi; 408ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 409ca632f55SGrant Likely 410ca632f55SGrant Likely mcspi = spi_master_get_devdata(spi->master); 411ca632f55SGrant Likely mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 412ca632f55SGrant Likely 413d7b4394eSShubhrajyoti D if (mcspi_dma->dma_tx) { 41453741ed8SRussell King struct dma_async_tx_descriptor *tx; 41553741ed8SRussell King 41653741ed8SRussell King dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); 41753741ed8SRussell King 4180ba1870fSFranklin S Cooper Jr tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, xfer->tx_sg.sgl, 4190ba1870fSFranklin S Cooper Jr xfer->tx_sg.nents, 4200ba1870fSFranklin S Cooper Jr DMA_MEM_TO_DEV, 4210ba1870fSFranklin S Cooper Jr DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 42253741ed8SRussell King if (tx) { 42353741ed8SRussell King tx->callback = omap2_mcspi_tx_callback; 42453741ed8SRussell King tx->callback_param = spi; 42553741ed8SRussell King dmaengine_submit(tx); 42653741ed8SRussell King } else { 42753741ed8SRussell King /* FIXME: fall back to PIO? */ 42853741ed8SRussell King } 42953741ed8SRussell King } 43053741ed8SRussell King dma_async_issue_pending(mcspi_dma->dma_tx); 431ca632f55SGrant Likely omap2_mcspi_set_dma_req(spi, 0, 1); 432ca632f55SGrant Likely 433ca632f55SGrant Likely } 434ca632f55SGrant Likely 435d7b4394eSShubhrajyoti D static unsigned 436d7b4394eSShubhrajyoti D omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, 437d7b4394eSShubhrajyoti D struct dma_slave_config cfg, 438d7b4394eSShubhrajyoti D unsigned es) 439d7b4394eSShubhrajyoti D { 440d7b4394eSShubhrajyoti D struct omap2_mcspi *mcspi; 441d7b4394eSShubhrajyoti D struct omap2_mcspi_dma *mcspi_dma; 4420ba1870fSFranklin S Cooper Jr unsigned int count, transfer_reduction = 0; 4430ba1870fSFranklin S Cooper Jr struct scatterlist *sg_out[2]; 4440ba1870fSFranklin S Cooper Jr int nb_sizes = 0, out_mapped_nents[2], ret, x; 4450ba1870fSFranklin S Cooper Jr size_t sizes[2]; 446d7b4394eSShubhrajyoti D u32 l; 447d7b4394eSShubhrajyoti D int elements = 0; 448d7b4394eSShubhrajyoti D int word_len, element_count; 449d7b4394eSShubhrajyoti D struct omap2_mcspi_cs *cs = spi->controller_state; 45081261359SAkinobu Mita void __iomem *chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; 45181261359SAkinobu Mita 452d7b4394eSShubhrajyoti D mcspi = spi_master_get_devdata(spi->master); 453d7b4394eSShubhrajyoti D mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 454d7b4394eSShubhrajyoti D count = xfer->len; 455d33f473dSIllia Smyrnov 4564bd00413SFranklin S Cooper Jr /* 4574bd00413SFranklin S Cooper Jr * In the "End-of-Transfer Procedure" section for DMA RX in OMAP35x TRM 4584bd00413SFranklin S Cooper Jr * it mentions reducing DMA transfer length by one element in master 4594bd00413SFranklin S Cooper Jr * normal mode. 4604bd00413SFranklin S Cooper Jr */ 461d33f473dSIllia Smyrnov if (mcspi->fifo_depth == 0) 4620ba1870fSFranklin S Cooper Jr transfer_reduction = es; 463d33f473dSIllia Smyrnov 464d7b4394eSShubhrajyoti D word_len = cs->word_len; 465d7b4394eSShubhrajyoti D l = mcspi_cached_chconf0(spi); 466d7b4394eSShubhrajyoti D 467d7b4394eSShubhrajyoti D if (word_len <= 8) 468d7b4394eSShubhrajyoti D element_count = count; 469d7b4394eSShubhrajyoti D else if (word_len <= 16) 470d7b4394eSShubhrajyoti D element_count = count >> 1; 471d7b4394eSShubhrajyoti D else /* word_len <= 32 */ 472d7b4394eSShubhrajyoti D element_count = count >> 2; 473d7b4394eSShubhrajyoti D 474d7b4394eSShubhrajyoti D if (mcspi_dma->dma_rx) { 475d7b4394eSShubhrajyoti D struct dma_async_tx_descriptor *tx; 476d7b4394eSShubhrajyoti D 477d7b4394eSShubhrajyoti D dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); 478d7b4394eSShubhrajyoti D 4794bd00413SFranklin S Cooper Jr /* 4804bd00413SFranklin S Cooper Jr * Reduce DMA transfer length by one more if McSPI is 4814bd00413SFranklin S Cooper Jr * configured in turbo mode. 4824bd00413SFranklin S Cooper Jr */ 483d33f473dSIllia Smyrnov if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) 4840ba1870fSFranklin S Cooper Jr transfer_reduction += es; 485d7b4394eSShubhrajyoti D 4860ba1870fSFranklin S Cooper Jr if (transfer_reduction) { 4870ba1870fSFranklin S Cooper Jr /* Split sgl into two. The second sgl won't be used. */ 4880ba1870fSFranklin S Cooper Jr sizes[0] = count - transfer_reduction; 4890ba1870fSFranklin S Cooper Jr sizes[1] = transfer_reduction; 4900ba1870fSFranklin S Cooper Jr nb_sizes = 2; 4910ba1870fSFranklin S Cooper Jr } else { 4920ba1870fSFranklin S Cooper Jr /* 4930ba1870fSFranklin S Cooper Jr * Don't bother splitting the sgl. This essentially 4940ba1870fSFranklin S Cooper Jr * clones the original sgl. 4950ba1870fSFranklin S Cooper Jr */ 4960ba1870fSFranklin S Cooper Jr sizes[0] = count; 4970ba1870fSFranklin S Cooper Jr nb_sizes = 1; 4980ba1870fSFranklin S Cooper Jr } 499d7b4394eSShubhrajyoti D 5000ba1870fSFranklin S Cooper Jr ret = sg_split(xfer->rx_sg.sgl, xfer->rx_sg.nents, 5010ba1870fSFranklin S Cooper Jr 0, nb_sizes, 5020ba1870fSFranklin S Cooper Jr sizes, 5030ba1870fSFranklin S Cooper Jr sg_out, out_mapped_nents, 5040ba1870fSFranklin S Cooper Jr GFP_KERNEL); 5050ba1870fSFranklin S Cooper Jr 5060ba1870fSFranklin S Cooper Jr if (ret < 0) { 5070ba1870fSFranklin S Cooper Jr dev_err(&spi->dev, "sg_split failed\n"); 5080ba1870fSFranklin S Cooper Jr return 0; 5090ba1870fSFranklin S Cooper Jr } 5100ba1870fSFranklin S Cooper Jr 5110ba1870fSFranklin S Cooper Jr tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, 5120ba1870fSFranklin S Cooper Jr sg_out[0], 5130ba1870fSFranklin S Cooper Jr out_mapped_nents[0], 5140ba1870fSFranklin S Cooper Jr DMA_DEV_TO_MEM, 5150ba1870fSFranklin S Cooper Jr DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 516d7b4394eSShubhrajyoti D if (tx) { 517d7b4394eSShubhrajyoti D tx->callback = omap2_mcspi_rx_callback; 518d7b4394eSShubhrajyoti D tx->callback_param = spi; 519d7b4394eSShubhrajyoti D dmaengine_submit(tx); 520d7b4394eSShubhrajyoti D } else { 521d7b4394eSShubhrajyoti D /* FIXME: fall back to PIO? */ 522d7b4394eSShubhrajyoti D } 523d7b4394eSShubhrajyoti D } 524d7b4394eSShubhrajyoti D 525d7b4394eSShubhrajyoti D dma_async_issue_pending(mcspi_dma->dma_rx); 526d7b4394eSShubhrajyoti D omap2_mcspi_set_dma_req(spi, 1, 1); 527d7b4394eSShubhrajyoti D 528*89e8b9cbSVignesh R ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_rx_completion); 529*89e8b9cbSVignesh R if (ret || mcspi->slave_aborted) { 530*89e8b9cbSVignesh R dmaengine_terminate_sync(mcspi_dma->dma_rx); 531*89e8b9cbSVignesh R omap2_mcspi_set_dma_req(spi, 1, 0); 532*89e8b9cbSVignesh R return 0; 533*89e8b9cbSVignesh R } 5340ba1870fSFranklin S Cooper Jr 5350ba1870fSFranklin S Cooper Jr for (x = 0; x < nb_sizes; x++) 5360ba1870fSFranklin S Cooper Jr kfree(sg_out[x]); 537d33f473dSIllia Smyrnov 538d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) 539d33f473dSIllia Smyrnov return count; 540d33f473dSIllia Smyrnov 5414bd00413SFranklin S Cooper Jr /* 5424bd00413SFranklin S Cooper Jr * Due to the DMA transfer length reduction the missing bytes must 5434bd00413SFranklin S Cooper Jr * be read manually to receive all of the expected data. 5444bd00413SFranklin S Cooper Jr */ 545ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 546ca632f55SGrant Likely 54753741ed8SRussell King elements = element_count - 1; 54853741ed8SRussell King 549ca632f55SGrant Likely if (l & OMAP2_MCSPI_CHCONF_TURBO) { 55053741ed8SRussell King elements--; 551ca632f55SGrant Likely 55281261359SAkinobu Mita if (!mcspi_wait_for_reg_bit(chstat_reg, 55381261359SAkinobu Mita OMAP2_MCSPI_CHSTAT_RXS)) { 554ca632f55SGrant Likely u32 w; 555ca632f55SGrant Likely 556ca632f55SGrant Likely w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); 557ca632f55SGrant Likely if (word_len <= 8) 558ca632f55SGrant Likely ((u8 *)xfer->rx_buf)[elements++] = w; 559ca632f55SGrant Likely else if (word_len <= 16) 560ca632f55SGrant Likely ((u16 *)xfer->rx_buf)[elements++] = w; 561ca632f55SGrant Likely else /* word_len <= 32 */ 562ca632f55SGrant Likely ((u32 *)xfer->rx_buf)[elements++] = w; 563ca632f55SGrant Likely } else { 56456cd5c15SIllia Smyrnov int bytes_per_word = mcspi_bytes_per_word(word_len); 565a1829d2bSJarkko Nikula dev_err(&spi->dev, "DMA RX penultimate word empty\n"); 56656cd5c15SIllia Smyrnov count -= (bytes_per_word << 1); 567ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 568ca632f55SGrant Likely return count; 569ca632f55SGrant Likely } 570ca632f55SGrant Likely } 57181261359SAkinobu Mita if (!mcspi_wait_for_reg_bit(chstat_reg, OMAP2_MCSPI_CHSTAT_RXS)) { 572ca632f55SGrant Likely u32 w; 573ca632f55SGrant Likely 574ca632f55SGrant Likely w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); 575ca632f55SGrant Likely if (word_len <= 8) 576ca632f55SGrant Likely ((u8 *)xfer->rx_buf)[elements] = w; 577ca632f55SGrant Likely else if (word_len <= 16) 578ca632f55SGrant Likely ((u16 *)xfer->rx_buf)[elements] = w; 579ca632f55SGrant Likely else /* word_len <= 32 */ 580ca632f55SGrant Likely ((u32 *)xfer->rx_buf)[elements] = w; 581ca632f55SGrant Likely } else { 582a1829d2bSJarkko Nikula dev_err(&spi->dev, "DMA RX last word empty\n"); 58356cd5c15SIllia Smyrnov count -= mcspi_bytes_per_word(word_len); 584ca632f55SGrant Likely } 585ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 586d7b4394eSShubhrajyoti D return count; 587ca632f55SGrant Likely } 588d7b4394eSShubhrajyoti D 589d7b4394eSShubhrajyoti D static unsigned 590d7b4394eSShubhrajyoti D omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) 591d7b4394eSShubhrajyoti D { 592d7b4394eSShubhrajyoti D struct omap2_mcspi *mcspi; 593d7b4394eSShubhrajyoti D struct omap2_mcspi_cs *cs = spi->controller_state; 594d7b4394eSShubhrajyoti D struct omap2_mcspi_dma *mcspi_dma; 595d7b4394eSShubhrajyoti D unsigned int count; 596d7b4394eSShubhrajyoti D u8 *rx; 597d7b4394eSShubhrajyoti D const u8 *tx; 598d7b4394eSShubhrajyoti D struct dma_slave_config cfg; 599d7b4394eSShubhrajyoti D enum dma_slave_buswidth width; 600d7b4394eSShubhrajyoti D unsigned es; 601e47a682aSShubhrajyoti D void __iomem *chstat_reg; 602d33f473dSIllia Smyrnov void __iomem *irqstat_reg; 603d33f473dSIllia Smyrnov int wait_res; 604d7b4394eSShubhrajyoti D 605d7b4394eSShubhrajyoti D mcspi = spi_master_get_devdata(spi->master); 606d7b4394eSShubhrajyoti D mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 607d7b4394eSShubhrajyoti D 608d7b4394eSShubhrajyoti D if (cs->word_len <= 8) { 609d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_1_BYTE; 610d7b4394eSShubhrajyoti D es = 1; 611d7b4394eSShubhrajyoti D } else if (cs->word_len <= 16) { 612d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_2_BYTES; 613d7b4394eSShubhrajyoti D es = 2; 614d7b4394eSShubhrajyoti D } else { 615d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_4_BYTES; 616d7b4394eSShubhrajyoti D es = 4; 617d7b4394eSShubhrajyoti D } 618d7b4394eSShubhrajyoti D 619d33f473dSIllia Smyrnov count = xfer->len; 620d33f473dSIllia Smyrnov 621d7b4394eSShubhrajyoti D memset(&cfg, 0, sizeof(cfg)); 622d7b4394eSShubhrajyoti D cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; 623d7b4394eSShubhrajyoti D cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; 624d7b4394eSShubhrajyoti D cfg.src_addr_width = width; 625d7b4394eSShubhrajyoti D cfg.dst_addr_width = width; 626b682cffaSVignesh R cfg.src_maxburst = es; 627b682cffaSVignesh R cfg.dst_maxburst = es; 628d7b4394eSShubhrajyoti D 629d7b4394eSShubhrajyoti D rx = xfer->rx_buf; 630d7b4394eSShubhrajyoti D tx = xfer->tx_buf; 631d7b4394eSShubhrajyoti D 632*89e8b9cbSVignesh R mcspi->slave_aborted = false; 633*89e8b9cbSVignesh R reinit_completion(&mcspi_dma->dma_tx_completion); 634*89e8b9cbSVignesh R reinit_completion(&mcspi_dma->dma_rx_completion); 635*89e8b9cbSVignesh R reinit_completion(&mcspi->txdone); 636*89e8b9cbSVignesh R if (tx) { 637*89e8b9cbSVignesh R /* Enable EOW IRQ to know end of tx in slave mode */ 638*89e8b9cbSVignesh R if (spi_controller_is_slave(spi->master)) 639*89e8b9cbSVignesh R mcspi_write_reg(spi->master, 640*89e8b9cbSVignesh R OMAP2_MCSPI_IRQENABLE, 641*89e8b9cbSVignesh R OMAP2_MCSPI_IRQSTATUS_EOW); 642d7b4394eSShubhrajyoti D omap2_mcspi_tx_dma(spi, xfer, cfg); 643*89e8b9cbSVignesh R } 644d7b4394eSShubhrajyoti D 645d7b4394eSShubhrajyoti D if (rx != NULL) 646e47a682aSShubhrajyoti D count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); 647d7b4394eSShubhrajyoti D 648e47a682aSShubhrajyoti D if (tx != NULL) { 649*89e8b9cbSVignesh R int ret; 650*89e8b9cbSVignesh R 651*89e8b9cbSVignesh R ret = mcspi_wait_for_completion(mcspi, &mcspi_dma->dma_tx_completion); 652*89e8b9cbSVignesh R if (ret || mcspi->slave_aborted) { 653*89e8b9cbSVignesh R dmaengine_terminate_sync(mcspi_dma->dma_tx); 654*89e8b9cbSVignesh R omap2_mcspi_set_dma_req(spi, 0, 0); 655*89e8b9cbSVignesh R return 0; 656*89e8b9cbSVignesh R } 657*89e8b9cbSVignesh R 658*89e8b9cbSVignesh R if (spi_controller_is_slave(mcspi->master)) { 659*89e8b9cbSVignesh R ret = mcspi_wait_for_completion(mcspi, &mcspi->txdone); 660*89e8b9cbSVignesh R if (ret || mcspi->slave_aborted) 661*89e8b9cbSVignesh R return 0; 662*89e8b9cbSVignesh R } 663e47a682aSShubhrajyoti D 664d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) { 665d33f473dSIllia Smyrnov irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; 666d33f473dSIllia Smyrnov 667d33f473dSIllia Smyrnov if (mcspi_wait_for_reg_bit(irqstat_reg, 668d33f473dSIllia Smyrnov OMAP2_MCSPI_IRQSTATUS_EOW) < 0) 669d33f473dSIllia Smyrnov dev_err(&spi->dev, "EOW timed out\n"); 670d33f473dSIllia Smyrnov 671d33f473dSIllia Smyrnov mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS, 672d33f473dSIllia Smyrnov OMAP2_MCSPI_IRQSTATUS_EOW); 673d33f473dSIllia Smyrnov } 674d33f473dSIllia Smyrnov 675e47a682aSShubhrajyoti D /* for TX_ONLY mode, be sure all words have shifted out */ 676e47a682aSShubhrajyoti D if (rx == NULL) { 677d33f473dSIllia Smyrnov chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; 678d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) { 679d33f473dSIllia Smyrnov wait_res = mcspi_wait_for_reg_bit(chstat_reg, 680d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_TXFFE); 681d33f473dSIllia Smyrnov if (wait_res < 0) 682d33f473dSIllia Smyrnov dev_err(&spi->dev, "TXFFE timed out\n"); 683d33f473dSIllia Smyrnov } else { 684d33f473dSIllia Smyrnov wait_res = mcspi_wait_for_reg_bit(chstat_reg, 685d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_TXS); 686d33f473dSIllia Smyrnov if (wait_res < 0) 687e47a682aSShubhrajyoti D dev_err(&spi->dev, "TXS timed out\n"); 688d33f473dSIllia Smyrnov } 689d33f473dSIllia Smyrnov if (wait_res >= 0 && 690d33f473dSIllia Smyrnov (mcspi_wait_for_reg_bit(chstat_reg, 691d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_EOT) < 0)) 692e47a682aSShubhrajyoti D dev_err(&spi->dev, "EOT timed out\n"); 693e47a682aSShubhrajyoti D } 694e47a682aSShubhrajyoti D } 695ca632f55SGrant Likely return count; 696ca632f55SGrant Likely } 697ca632f55SGrant Likely 698ca632f55SGrant Likely static unsigned 699ca632f55SGrant Likely omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) 700ca632f55SGrant Likely { 701ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 702ca632f55SGrant Likely unsigned int count, c; 703ca632f55SGrant Likely u32 l; 704ca632f55SGrant Likely void __iomem *base = cs->base; 705ca632f55SGrant Likely void __iomem *tx_reg; 706ca632f55SGrant Likely void __iomem *rx_reg; 707ca632f55SGrant Likely void __iomem *chstat_reg; 708ca632f55SGrant Likely int word_len; 709ca632f55SGrant Likely 710ca632f55SGrant Likely count = xfer->len; 711ca632f55SGrant Likely c = count; 712ca632f55SGrant Likely word_len = cs->word_len; 713ca632f55SGrant Likely 714ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 715ca632f55SGrant Likely 716ca632f55SGrant Likely /* We store the pre-calculated register addresses on stack to speed 717ca632f55SGrant Likely * up the transfer loop. */ 718ca632f55SGrant Likely tx_reg = base + OMAP2_MCSPI_TX0; 719ca632f55SGrant Likely rx_reg = base + OMAP2_MCSPI_RX0; 720ca632f55SGrant Likely chstat_reg = base + OMAP2_MCSPI_CHSTAT0; 721ca632f55SGrant Likely 722ca632f55SGrant Likely if (c < (word_len>>3)) 723ca632f55SGrant Likely return 0; 724ca632f55SGrant Likely 725ca632f55SGrant Likely if (word_len <= 8) { 726ca632f55SGrant Likely u8 *rx; 727ca632f55SGrant Likely const u8 *tx; 728ca632f55SGrant Likely 729ca632f55SGrant Likely rx = xfer->rx_buf; 730ca632f55SGrant Likely tx = xfer->tx_buf; 731ca632f55SGrant Likely 732ca632f55SGrant Likely do { 733ca632f55SGrant Likely c -= 1; 734ca632f55SGrant Likely if (tx != NULL) { 735ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 736ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 737ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 738ca632f55SGrant Likely goto out; 739ca632f55SGrant Likely } 740ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %02x\n", 741ca632f55SGrant Likely word_len, *tx); 74221b2ce5eSVictor Kamensky writel_relaxed(*tx++, tx_reg); 743ca632f55SGrant Likely } 744ca632f55SGrant Likely if (rx != NULL) { 745ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 746ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 747ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 748ca632f55SGrant Likely goto out; 749ca632f55SGrant Likely } 750ca632f55SGrant Likely 751ca632f55SGrant Likely if (c == 1 && tx == NULL && 752ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 753ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 75421b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 755ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %02x\n", 756ca632f55SGrant Likely word_len, *(rx - 1)); 757ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 758ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 759ca632f55SGrant Likely dev_err(&spi->dev, 760ca632f55SGrant Likely "RXS timed out\n"); 761ca632f55SGrant Likely goto out; 762ca632f55SGrant Likely } 763ca632f55SGrant Likely c = 0; 764ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 765ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 766ca632f55SGrant Likely } 767ca632f55SGrant Likely 76821b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 769ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %02x\n", 770ca632f55SGrant Likely word_len, *(rx - 1)); 771ca632f55SGrant Likely } 772ca632f55SGrant Likely } while (c); 773ca632f55SGrant Likely } else if (word_len <= 16) { 774ca632f55SGrant Likely u16 *rx; 775ca632f55SGrant Likely const u16 *tx; 776ca632f55SGrant Likely 777ca632f55SGrant Likely rx = xfer->rx_buf; 778ca632f55SGrant Likely tx = xfer->tx_buf; 779ca632f55SGrant Likely do { 780ca632f55SGrant Likely c -= 2; 781ca632f55SGrant Likely if (tx != NULL) { 782ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 783ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 784ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 785ca632f55SGrant Likely goto out; 786ca632f55SGrant Likely } 787ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %04x\n", 788ca632f55SGrant Likely word_len, *tx); 78921b2ce5eSVictor Kamensky writel_relaxed(*tx++, tx_reg); 790ca632f55SGrant Likely } 791ca632f55SGrant Likely if (rx != NULL) { 792ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 793ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 794ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 795ca632f55SGrant Likely goto out; 796ca632f55SGrant Likely } 797ca632f55SGrant Likely 798ca632f55SGrant Likely if (c == 2 && tx == NULL && 799ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 800ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 80121b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 802ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %04x\n", 803ca632f55SGrant Likely word_len, *(rx - 1)); 804ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 805ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 806ca632f55SGrant Likely dev_err(&spi->dev, 807ca632f55SGrant Likely "RXS timed out\n"); 808ca632f55SGrant Likely goto out; 809ca632f55SGrant Likely } 810ca632f55SGrant Likely c = 0; 811ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 812ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 813ca632f55SGrant Likely } 814ca632f55SGrant Likely 81521b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 816ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %04x\n", 817ca632f55SGrant Likely word_len, *(rx - 1)); 818ca632f55SGrant Likely } 819ca632f55SGrant Likely } while (c >= 2); 820ca632f55SGrant Likely } else if (word_len <= 32) { 821ca632f55SGrant Likely u32 *rx; 822ca632f55SGrant Likely const u32 *tx; 823ca632f55SGrant Likely 824ca632f55SGrant Likely rx = xfer->rx_buf; 825ca632f55SGrant Likely tx = xfer->tx_buf; 826ca632f55SGrant Likely do { 827ca632f55SGrant Likely c -= 4; 828ca632f55SGrant Likely if (tx != NULL) { 829ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 830ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 831ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 832ca632f55SGrant Likely goto out; 833ca632f55SGrant Likely } 834ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %08x\n", 835ca632f55SGrant Likely word_len, *tx); 83621b2ce5eSVictor Kamensky writel_relaxed(*tx++, tx_reg); 837ca632f55SGrant Likely } 838ca632f55SGrant Likely if (rx != NULL) { 839ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 840ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 841ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 842ca632f55SGrant Likely goto out; 843ca632f55SGrant Likely } 844ca632f55SGrant Likely 845ca632f55SGrant Likely if (c == 4 && tx == NULL && 846ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 847ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 84821b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 849ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %08x\n", 850ca632f55SGrant Likely word_len, *(rx - 1)); 851ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 852ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 853ca632f55SGrant Likely dev_err(&spi->dev, 854ca632f55SGrant Likely "RXS timed out\n"); 855ca632f55SGrant Likely goto out; 856ca632f55SGrant Likely } 857ca632f55SGrant Likely c = 0; 858ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 859ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 860ca632f55SGrant Likely } 861ca632f55SGrant Likely 86221b2ce5eSVictor Kamensky *rx++ = readl_relaxed(rx_reg); 863ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %08x\n", 864ca632f55SGrant Likely word_len, *(rx - 1)); 865ca632f55SGrant Likely } 866ca632f55SGrant Likely } while (c >= 4); 867ca632f55SGrant Likely } 868ca632f55SGrant Likely 869ca632f55SGrant Likely /* for TX_ONLY mode, be sure all words have shifted out */ 870ca632f55SGrant Likely if (xfer->rx_buf == NULL) { 871ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 872ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 873ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 874ca632f55SGrant Likely } else if (mcspi_wait_for_reg_bit(chstat_reg, 875ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_EOT) < 0) 876ca632f55SGrant Likely dev_err(&spi->dev, "EOT timed out\n"); 877ca632f55SGrant Likely 878ca632f55SGrant Likely /* disable chan to purge rx datas received in TX_ONLY transfer, 879ca632f55SGrant Likely * otherwise these rx datas will affect the direct following 880ca632f55SGrant Likely * RX_ONLY transfer. 881ca632f55SGrant Likely */ 882ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 883ca632f55SGrant Likely } 884ca632f55SGrant Likely out: 885ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 886ca632f55SGrant Likely return count - c; 887ca632f55SGrant Likely } 888ca632f55SGrant Likely 889ca632f55SGrant Likely static u32 omap2_mcspi_calc_divisor(u32 speed_hz) 890ca632f55SGrant Likely { 891ca632f55SGrant Likely u32 div; 892ca632f55SGrant Likely 893ca632f55SGrant Likely for (div = 0; div < 15; div++) 894ca632f55SGrant Likely if (speed_hz >= (OMAP2_MCSPI_MAX_FREQ >> div)) 895ca632f55SGrant Likely return div; 896ca632f55SGrant Likely 897ca632f55SGrant Likely return 15; 898ca632f55SGrant Likely } 899ca632f55SGrant Likely 900ca632f55SGrant Likely /* called only when no transfer is active to this device */ 901ca632f55SGrant Likely static int omap2_mcspi_setup_transfer(struct spi_device *spi, 902ca632f55SGrant Likely struct spi_transfer *t) 903ca632f55SGrant Likely { 904ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 905ca632f55SGrant Likely struct omap2_mcspi *mcspi; 906faee9b05SStefan Sørensen u32 l = 0, clkd = 0, div, extclk = 0, clkg = 0; 907ca632f55SGrant Likely u8 word_len = spi->bits_per_word; 908ca632f55SGrant Likely u32 speed_hz = spi->max_speed_hz; 909ca632f55SGrant Likely 910ca632f55SGrant Likely mcspi = spi_master_get_devdata(spi->master); 911ca632f55SGrant Likely 912ca632f55SGrant Likely if (t != NULL && t->bits_per_word) 913ca632f55SGrant Likely word_len = t->bits_per_word; 914ca632f55SGrant Likely 915ca632f55SGrant Likely cs->word_len = word_len; 916ca632f55SGrant Likely 917ca632f55SGrant Likely if (t && t->speed_hz) 918ca632f55SGrant Likely speed_hz = t->speed_hz; 919ca632f55SGrant Likely 920ca632f55SGrant Likely speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ); 921faee9b05SStefan Sørensen if (speed_hz < (OMAP2_MCSPI_MAX_FREQ / OMAP2_MCSPI_MAX_DIVIDER)) { 922faee9b05SStefan Sørensen clkd = omap2_mcspi_calc_divisor(speed_hz); 923faee9b05SStefan Sørensen speed_hz = OMAP2_MCSPI_MAX_FREQ >> clkd; 924faee9b05SStefan Sørensen clkg = 0; 925faee9b05SStefan Sørensen } else { 926faee9b05SStefan Sørensen div = (OMAP2_MCSPI_MAX_FREQ + speed_hz - 1) / speed_hz; 927faee9b05SStefan Sørensen speed_hz = OMAP2_MCSPI_MAX_FREQ / div; 928faee9b05SStefan Sørensen clkd = (div - 1) & 0xf; 929faee9b05SStefan Sørensen extclk = (div - 1) >> 4; 930faee9b05SStefan Sørensen clkg = OMAP2_MCSPI_CHCONF_CLKG; 931faee9b05SStefan Sørensen } 932ca632f55SGrant Likely 933ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 934ca632f55SGrant Likely 935ca632f55SGrant Likely /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS 936ca632f55SGrant Likely * REVISIT: this controller could support SPI_3WIRE mode. 937ca632f55SGrant Likely */ 9382cd45179SDaniel Mack if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) { 9390384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_IS; 9400384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_DPE1; 941ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_DPE0; 9420384e90bSDaniel Mack } else { 9430384e90bSDaniel Mack l |= OMAP2_MCSPI_CHCONF_IS; 9440384e90bSDaniel Mack l |= OMAP2_MCSPI_CHCONF_DPE1; 9450384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_DPE0; 9460384e90bSDaniel Mack } 947ca632f55SGrant Likely 948ca632f55SGrant Likely /* wordlength */ 949ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_WL_MASK; 950ca632f55SGrant Likely l |= (word_len - 1) << 7; 951ca632f55SGrant Likely 952ca632f55SGrant Likely /* set chipselect polarity; manage with FORCE */ 953ca632f55SGrant Likely if (!(spi->mode & SPI_CS_HIGH)) 954ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_EPOL; /* active-low; normal */ 955ca632f55SGrant Likely else 956ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_EPOL; 957ca632f55SGrant Likely 958ca632f55SGrant Likely /* set clock divisor */ 959ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK; 960faee9b05SStefan Sørensen l |= clkd << 2; 961faee9b05SStefan Sørensen 962faee9b05SStefan Sørensen /* set clock granularity */ 963faee9b05SStefan Sørensen l &= ~OMAP2_MCSPI_CHCONF_CLKG; 964faee9b05SStefan Sørensen l |= clkg; 965faee9b05SStefan Sørensen if (clkg) { 966faee9b05SStefan Sørensen cs->chctrl0 &= ~OMAP2_MCSPI_CHCTRL_EXTCLK_MASK; 967faee9b05SStefan Sørensen cs->chctrl0 |= extclk << 8; 968faee9b05SStefan Sørensen mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, cs->chctrl0); 969faee9b05SStefan Sørensen } 970ca632f55SGrant Likely 971ca632f55SGrant Likely /* set SPI mode 0..3 */ 972ca632f55SGrant Likely if (spi->mode & SPI_CPOL) 973ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_POL; 974ca632f55SGrant Likely else 975ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_POL; 976ca632f55SGrant Likely if (spi->mode & SPI_CPHA) 977ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_PHA; 978ca632f55SGrant Likely else 979ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_PHA; 980ca632f55SGrant Likely 981ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 982ca632f55SGrant Likely 98397ca0d6cSMark A. Greer cs->mode = spi->mode; 98497ca0d6cSMark A. Greer 985ca632f55SGrant Likely dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", 986faee9b05SStefan Sørensen speed_hz, 987ca632f55SGrant Likely (spi->mode & SPI_CPHA) ? "trailing" : "leading", 988ca632f55SGrant Likely (spi->mode & SPI_CPOL) ? "inverted" : "normal"); 989ca632f55SGrant Likely 990ca632f55SGrant Likely return 0; 991ca632f55SGrant Likely } 992ca632f55SGrant Likely 993ddc5cdf1STony Lindgren /* 994ddc5cdf1STony Lindgren * Note that we currently allow DMA only if we get a channel 995ddc5cdf1STony Lindgren * for both rx and tx. Otherwise we'll do PIO for both rx and tx. 996ddc5cdf1STony Lindgren */ 997ca632f55SGrant Likely static int omap2_mcspi_request_dma(struct spi_device *spi) 998ca632f55SGrant Likely { 999ca632f55SGrant Likely struct spi_master *master = spi->master; 1000ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1001ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 1002b085c612SPeter Ujfalusi int ret = 0; 1003ca632f55SGrant Likely 1004ca632f55SGrant Likely mcspi = spi_master_get_devdata(master); 1005ca632f55SGrant Likely mcspi_dma = mcspi->dma_channels + spi->chip_select; 1006ca632f55SGrant Likely 1007ca632f55SGrant Likely init_completion(&mcspi_dma->dma_rx_completion); 1008ca632f55SGrant Likely init_completion(&mcspi_dma->dma_tx_completion); 1009ca632f55SGrant Likely 1010b085c612SPeter Ujfalusi mcspi_dma->dma_rx = dma_request_chan(&master->dev, 101174f3aaadSMatt Porter mcspi_dma->dma_rx_ch_name); 1012b085c612SPeter Ujfalusi if (IS_ERR(mcspi_dma->dma_rx)) { 1013b085c612SPeter Ujfalusi ret = PTR_ERR(mcspi_dma->dma_rx); 101453741ed8SRussell King mcspi_dma->dma_rx = NULL; 1015ddc5cdf1STony Lindgren goto no_dma; 101653741ed8SRussell King } 1017ca632f55SGrant Likely 1018b085c612SPeter Ujfalusi mcspi_dma->dma_tx = dma_request_chan(&master->dev, 1019b085c612SPeter Ujfalusi mcspi_dma->dma_tx_ch_name); 1020b085c612SPeter Ujfalusi if (IS_ERR(mcspi_dma->dma_tx)) { 1021b085c612SPeter Ujfalusi ret = PTR_ERR(mcspi_dma->dma_tx); 1022b085c612SPeter Ujfalusi mcspi_dma->dma_tx = NULL; 1023b085c612SPeter Ujfalusi dma_release_channel(mcspi_dma->dma_rx); 1024b085c612SPeter Ujfalusi mcspi_dma->dma_rx = NULL; 1025b085c612SPeter Ujfalusi } 1026ddc5cdf1STony Lindgren 1027ddc5cdf1STony Lindgren no_dma: 1028b085c612SPeter Ujfalusi return ret; 1029ca632f55SGrant Likely } 1030ca632f55SGrant Likely 1031ca632f55SGrant Likely static int omap2_mcspi_setup(struct spi_device *spi) 1032ca632f55SGrant Likely { 1033ca632f55SGrant Likely int ret; 10341bd897f8SBenoit Cousson struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 10351bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1036ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 1037ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 1038ca632f55SGrant Likely 1039ca632f55SGrant Likely mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 1040ca632f55SGrant Likely 1041ca632f55SGrant Likely if (!cs) { 104210aa5a35SRussell King cs = kzalloc(sizeof *cs, GFP_KERNEL); 1043ca632f55SGrant Likely if (!cs) 1044ca632f55SGrant Likely return -ENOMEM; 1045ca632f55SGrant Likely cs->base = mcspi->base + spi->chip_select * 0x14; 1046ca632f55SGrant Likely cs->phys = mcspi->phys + spi->chip_select * 0x14; 104797ca0d6cSMark A. Greer cs->mode = 0; 1048ca632f55SGrant Likely cs->chconf0 = 0; 1049faee9b05SStefan Sørensen cs->chctrl0 = 0; 1050ca632f55SGrant Likely spi->controller_state = cs; 1051ca632f55SGrant Likely /* Link this to context save list */ 10521bd897f8SBenoit Cousson list_add_tail(&cs->node, &ctx->cs); 1053ca632f55SGrant Likely 1054bc7f9bbcSMichael Welling if (gpio_is_valid(spi->cs_gpio)) { 1055c4339ac7SMichael Welling ret = gpio_request(spi->cs_gpio, dev_name(&spi->dev)); 1056c4339ac7SMichael Welling if (ret) { 1057c4339ac7SMichael Welling dev_err(&spi->dev, "failed to request gpio\n"); 1058c4339ac7SMichael Welling return ret; 1059c4339ac7SMichael Welling } 10602f538c01SMichael Welling gpio_direction_output(spi->cs_gpio, 10612f538c01SMichael Welling !(spi->mode & SPI_CS_HIGH)); 10622f538c01SMichael Welling } 10632f538c01SMichael Welling } 10642f538c01SMichael Welling 10652f538c01SMichael Welling if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) { 10662f538c01SMichael Welling ret = omap2_mcspi_request_dma(spi); 1067b085c612SPeter Ujfalusi if (ret) 1068b085c612SPeter Ujfalusi dev_warn(&spi->dev, "not using DMA for McSPI (%d)\n", 1069b085c612SPeter Ujfalusi ret); 1070bc7f9bbcSMichael Welling } 1071bc7f9bbcSMichael Welling 1072034d3dc9SShubhrajyoti D ret = pm_runtime_get_sync(mcspi->dev); 10735a686b2cSTony Lindgren if (ret < 0) { 10745a686b2cSTony Lindgren pm_runtime_put_noidle(mcspi->dev); 10755a686b2cSTony Lindgren 1076ca632f55SGrant Likely return ret; 10775a686b2cSTony Lindgren } 1078ca632f55SGrant Likely 1079ca632f55SGrant Likely ret = omap2_mcspi_setup_transfer(spi, NULL); 1080034d3dc9SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 1081034d3dc9SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 1082ca632f55SGrant Likely 1083ca632f55SGrant Likely return ret; 1084ca632f55SGrant Likely } 1085ca632f55SGrant Likely 1086ca632f55SGrant Likely static void omap2_mcspi_cleanup(struct spi_device *spi) 1087ca632f55SGrant Likely { 1088ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1089ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 1090ca632f55SGrant Likely struct omap2_mcspi_cs *cs; 1091ca632f55SGrant Likely 1092ca632f55SGrant Likely mcspi = spi_master_get_devdata(spi->master); 1093ca632f55SGrant Likely 1094ca632f55SGrant Likely if (spi->controller_state) { 1095ca632f55SGrant Likely /* Unlink controller state from context save list */ 1096ca632f55SGrant Likely cs = spi->controller_state; 1097ca632f55SGrant Likely list_del(&cs->node); 1098ca632f55SGrant Likely 109910aa5a35SRussell King kfree(cs); 1100ca632f55SGrant Likely } 1101ca632f55SGrant Likely 1102ca632f55SGrant Likely if (spi->chip_select < spi->master->num_chipselect) { 1103ca632f55SGrant Likely mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 1104ca632f55SGrant Likely 110553741ed8SRussell King if (mcspi_dma->dma_rx) { 110653741ed8SRussell King dma_release_channel(mcspi_dma->dma_rx); 110753741ed8SRussell King mcspi_dma->dma_rx = NULL; 1108ca632f55SGrant Likely } 110953741ed8SRussell King if (mcspi_dma->dma_tx) { 111053741ed8SRussell King dma_release_channel(mcspi_dma->dma_tx); 111153741ed8SRussell King mcspi_dma->dma_tx = NULL; 1112ca632f55SGrant Likely } 1113ca632f55SGrant Likely } 1114bc7f9bbcSMichael Welling 1115bc7f9bbcSMichael Welling if (gpio_is_valid(spi->cs_gpio)) 1116bc7f9bbcSMichael Welling gpio_free(spi->cs_gpio); 1117ca632f55SGrant Likely } 1118ca632f55SGrant Likely 1119*89e8b9cbSVignesh R static irqreturn_t omap2_mcspi_irq_handler(int irq, void *data) 1120*89e8b9cbSVignesh R { 1121*89e8b9cbSVignesh R struct omap2_mcspi *mcspi = data; 1122*89e8b9cbSVignesh R u32 irqstat; 1123*89e8b9cbSVignesh R 1124*89e8b9cbSVignesh R irqstat = mcspi_read_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS); 1125*89e8b9cbSVignesh R if (!irqstat) 1126*89e8b9cbSVignesh R return IRQ_NONE; 1127*89e8b9cbSVignesh R 1128*89e8b9cbSVignesh R /* Disable IRQ and wakeup slave xfer task */ 1129*89e8b9cbSVignesh R mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQENABLE, 0); 1130*89e8b9cbSVignesh R if (irqstat & OMAP2_MCSPI_IRQSTATUS_EOW) 1131*89e8b9cbSVignesh R complete(&mcspi->txdone); 1132*89e8b9cbSVignesh R 1133*89e8b9cbSVignesh R return IRQ_HANDLED; 1134*89e8b9cbSVignesh R } 1135*89e8b9cbSVignesh R 1136*89e8b9cbSVignesh R static int omap2_mcspi_slave_abort(struct spi_master *master) 1137*89e8b9cbSVignesh R { 1138*89e8b9cbSVignesh R struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 1139*89e8b9cbSVignesh R struct omap2_mcspi_dma *mcspi_dma = mcspi->dma_channels; 1140*89e8b9cbSVignesh R 1141*89e8b9cbSVignesh R mcspi->slave_aborted = true; 1142*89e8b9cbSVignesh R complete(&mcspi_dma->dma_rx_completion); 1143*89e8b9cbSVignesh R complete(&mcspi_dma->dma_tx_completion); 1144*89e8b9cbSVignesh R complete(&mcspi->txdone); 1145*89e8b9cbSVignesh R 1146*89e8b9cbSVignesh R return 0; 1147*89e8b9cbSVignesh R } 1148*89e8b9cbSVignesh R 11490ba1870fSFranklin S Cooper Jr static int omap2_mcspi_transfer_one(struct spi_master *master, 11500ba1870fSFranklin S Cooper Jr struct spi_device *spi, 11510ba1870fSFranklin S Cooper Jr struct spi_transfer *t) 1152ca632f55SGrant Likely { 1153ca632f55SGrant Likely 1154ca632f55SGrant Likely /* We only enable one channel at a time -- the one whose message is 11555fda88f5SShubhrajyoti D * -- although this controller would gladly 1156ca632f55SGrant Likely * arbitrate among multiple channels. This corresponds to "single 1157ca632f55SGrant Likely * channel" master mode. As a side effect, we need to manage the 1158ca632f55SGrant Likely * chipselect with the FORCE bit ... CS != channel enable. 1159ca632f55SGrant Likely */ 11605fda88f5SShubhrajyoti D 11610ba1870fSFranklin S Cooper Jr struct omap2_mcspi *mcspi; 1162ddc5cdf1STony Lindgren struct omap2_mcspi_dma *mcspi_dma; 1163ca632f55SGrant Likely struct omap2_mcspi_cs *cs; 1164ca632f55SGrant Likely struct omap2_mcspi_device_config *cd; 1165ca632f55SGrant Likely int par_override = 0; 1166ca632f55SGrant Likely int status = 0; 1167ca632f55SGrant Likely u32 chconf; 1168ca632f55SGrant Likely 11690ba1870fSFranklin S Cooper Jr mcspi = spi_master_get_devdata(master); 1170ddc5cdf1STony Lindgren mcspi_dma = mcspi->dma_channels + spi->chip_select; 1171ca632f55SGrant Likely cs = spi->controller_state; 1172ca632f55SGrant Likely cd = spi->controller_data; 1173ca632f55SGrant Likely 117497ca0d6cSMark A. Greer /* 117597ca0d6cSMark A. Greer * The slave driver could have changed spi->mode in which case 117697ca0d6cSMark A. Greer * it will be different from cs->mode (the current hardware setup). 117797ca0d6cSMark A. Greer * If so, set par_override (even though its not a parity issue) so 117897ca0d6cSMark A. Greer * omap2_mcspi_setup_transfer will be called to configure the hardware 117997ca0d6cSMark A. Greer * with the correct mode on the first iteration of the loop below. 118097ca0d6cSMark A. Greer */ 118197ca0d6cSMark A. Greer if (spi->mode != cs->mode) 118297ca0d6cSMark A. Greer par_override = 1; 118397ca0d6cSMark A. Greer 1184d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 0); 1185b28cb941SMichael Welling 1186a06b430fSMichael Welling if (gpio_is_valid(spi->cs_gpio)) 1187a06b430fSMichael Welling omap2_mcspi_set_cs(spi, spi->mode & SPI_CS_HIGH); 1188a06b430fSMichael Welling 11892bd16e3eSStefan Sørensen if (par_override || 11902bd16e3eSStefan Sørensen (t->speed_hz != spi->max_speed_hz) || 11912bd16e3eSStefan Sørensen (t->bits_per_word != spi->bits_per_word)) { 1192ca632f55SGrant Likely par_override = 1; 1193ca632f55SGrant Likely status = omap2_mcspi_setup_transfer(spi, t); 1194ca632f55SGrant Likely if (status < 0) 1195b28cb941SMichael Welling goto out; 11962bd16e3eSStefan Sørensen if (t->speed_hz == spi->max_speed_hz && 11972bd16e3eSStefan Sørensen t->bits_per_word == spi->bits_per_word) 1198ca632f55SGrant Likely par_override = 0; 1199ca632f55SGrant Likely } 12005cbc7ca9SMatthias Brugger if (cd && cd->cs_per_word) { 12015cbc7ca9SMatthias Brugger chconf = mcspi->ctx.modulctrl; 12025cbc7ca9SMatthias Brugger chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; 12035cbc7ca9SMatthias Brugger mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf); 12045cbc7ca9SMatthias Brugger mcspi->ctx.modulctrl = 12055cbc7ca9SMatthias Brugger mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 12065cbc7ca9SMatthias Brugger } 12075cbc7ca9SMatthias Brugger 1208ca632f55SGrant Likely chconf = mcspi_cached_chconf0(spi); 1209ca632f55SGrant Likely chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; 1210ca632f55SGrant Likely chconf &= ~OMAP2_MCSPI_CHCONF_TURBO; 1211ca632f55SGrant Likely 1212ca632f55SGrant Likely if (t->tx_buf == NULL) 1213ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; 1214ca632f55SGrant Likely else if (t->rx_buf == NULL) 1215ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; 1216ca632f55SGrant Likely 1217ca632f55SGrant Likely if (cd && cd->turbo_mode && t->tx_buf == NULL) { 1218ca632f55SGrant Likely /* Turbo mode is for more than one word */ 1219ca632f55SGrant Likely if (t->len > ((cs->word_len + 7) >> 3)) 1220ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TURBO; 1221ca632f55SGrant Likely } 1222ca632f55SGrant Likely 1223ca632f55SGrant Likely mcspi_write_chconf0(spi, chconf); 1224ca632f55SGrant Likely 1225ca632f55SGrant Likely if (t->len) { 1226ca632f55SGrant Likely unsigned count; 1227ca632f55SGrant Likely 1228d33f473dSIllia Smyrnov if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && 12290ba1870fSFranklin S Cooper Jr master->cur_msg_mapped && 12300ba1870fSFranklin S Cooper Jr master->can_dma(master, spi, t)) 1231d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 1); 1232d33f473dSIllia Smyrnov 1233d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 1); 1234d33f473dSIllia Smyrnov 1235ca632f55SGrant Likely /* RX_ONLY mode needs dummy data in TX reg */ 1236ca632f55SGrant Likely if (t->tx_buf == NULL) 123721b2ce5eSVictor Kamensky writel_relaxed(0, cs->base 1238ca632f55SGrant Likely + OMAP2_MCSPI_TX0); 1239ca632f55SGrant Likely 1240ddc5cdf1STony Lindgren if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && 12410ba1870fSFranklin S Cooper Jr master->cur_msg_mapped && 12420ba1870fSFranklin S Cooper Jr master->can_dma(master, spi, t)) 1243ca632f55SGrant Likely count = omap2_mcspi_txrx_dma(spi, t); 1244ca632f55SGrant Likely else 1245ca632f55SGrant Likely count = omap2_mcspi_txrx_pio(spi, t); 1246ca632f55SGrant Likely 1247ca632f55SGrant Likely if (count != t->len) { 1248ca632f55SGrant Likely status = -EIO; 1249b28cb941SMichael Welling goto out; 1250ca632f55SGrant Likely } 1251ca632f55SGrant Likely } 1252ca632f55SGrant Likely 1253d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 0); 1254d33f473dSIllia Smyrnov 1255d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) 1256d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 0); 1257b28cb941SMichael Welling 1258b28cb941SMichael Welling out: 1259ca632f55SGrant Likely /* Restore defaults if they were overriden */ 1260ca632f55SGrant Likely if (par_override) { 1261ca632f55SGrant Likely par_override = 0; 1262ca632f55SGrant Likely status = omap2_mcspi_setup_transfer(spi, NULL); 1263ca632f55SGrant Likely } 1264ca632f55SGrant Likely 12655cbc7ca9SMatthias Brugger if (cd && cd->cs_per_word) { 12665cbc7ca9SMatthias Brugger chconf = mcspi->ctx.modulctrl; 12675cbc7ca9SMatthias Brugger chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE; 12685cbc7ca9SMatthias Brugger mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf); 12695cbc7ca9SMatthias Brugger mcspi->ctx.modulctrl = 12705cbc7ca9SMatthias Brugger mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 12715cbc7ca9SMatthias Brugger } 12725cbc7ca9SMatthias Brugger 1273ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 1274ca632f55SGrant Likely 1275a06b430fSMichael Welling if (gpio_is_valid(spi->cs_gpio)) 1276a06b430fSMichael Welling omap2_mcspi_set_cs(spi, !(spi->mode & SPI_CS_HIGH)); 1277a06b430fSMichael Welling 1278d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0 && t) 1279d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 0); 1280ca632f55SGrant Likely 1281b28cb941SMichael Welling return status; 1282ca632f55SGrant Likely } 1283ca632f55SGrant Likely 1284468a3208SNeil Armstrong static int omap2_mcspi_prepare_message(struct spi_master *master, 1285468a3208SNeil Armstrong struct spi_message *msg) 1286468a3208SNeil Armstrong { 1287468a3208SNeil Armstrong struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 1288468a3208SNeil Armstrong struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1289468a3208SNeil Armstrong struct omap2_mcspi_cs *cs; 1290468a3208SNeil Armstrong 1291468a3208SNeil Armstrong /* Only a single channel can have the FORCE bit enabled 1292468a3208SNeil Armstrong * in its chconf0 register. 1293468a3208SNeil Armstrong * Scan all channels and disable them except the current one. 1294468a3208SNeil Armstrong * A FORCE can remain from a last transfer having cs_change enabled 1295468a3208SNeil Armstrong */ 1296468a3208SNeil Armstrong list_for_each_entry(cs, &ctx->cs, node) { 1297468a3208SNeil Armstrong if (msg->spi->controller_state == cs) 1298468a3208SNeil Armstrong continue; 1299468a3208SNeil Armstrong 1300468a3208SNeil Armstrong if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE)) { 1301468a3208SNeil Armstrong cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; 1302468a3208SNeil Armstrong writel_relaxed(cs->chconf0, 1303468a3208SNeil Armstrong cs->base + OMAP2_MCSPI_CHCONF0); 1304468a3208SNeil Armstrong readl_relaxed(cs->base + OMAP2_MCSPI_CHCONF0); 1305468a3208SNeil Armstrong } 1306468a3208SNeil Armstrong } 1307468a3208SNeil Armstrong 1308468a3208SNeil Armstrong return 0; 1309468a3208SNeil Armstrong } 1310468a3208SNeil Armstrong 13110ba1870fSFranklin S Cooper Jr static bool omap2_mcspi_can_dma(struct spi_master *master, 13120ba1870fSFranklin S Cooper Jr struct spi_device *spi, 13130ba1870fSFranklin S Cooper Jr struct spi_transfer *xfer) 1314ca632f55SGrant Likely { 1315*89e8b9cbSVignesh R struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 1316*89e8b9cbSVignesh R struct omap2_mcspi_dma *mcspi_dma = 1317*89e8b9cbSVignesh R &mcspi->dma_channels[spi->chip_select]; 1318*89e8b9cbSVignesh R 1319*89e8b9cbSVignesh R if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) 1320*89e8b9cbSVignesh R return false; 1321*89e8b9cbSVignesh R 1322*89e8b9cbSVignesh R if (spi_controller_is_slave(master)) 1323*89e8b9cbSVignesh R return true; 1324*89e8b9cbSVignesh R 13250ba1870fSFranklin S Cooper Jr return (xfer->len >= DMA_MIN_BYTES); 1326ca632f55SGrant Likely } 1327ca632f55SGrant Likely 1328*89e8b9cbSVignesh R static int omap2_mcspi_controller_setup(struct omap2_mcspi *mcspi) 1329ca632f55SGrant Likely { 1330ca632f55SGrant Likely struct spi_master *master = mcspi->master; 13311bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1332ca632f55SGrant Likely int ret = 0; 1333ca632f55SGrant Likely 1334034d3dc9SShubhrajyoti D ret = pm_runtime_get_sync(mcspi->dev); 13355a686b2cSTony Lindgren if (ret < 0) { 13365a686b2cSTony Lindgren pm_runtime_put_noidle(mcspi->dev); 13375a686b2cSTony Lindgren 1338ca632f55SGrant Likely return ret; 13395a686b2cSTony Lindgren } 1340ca632f55SGrant Likely 134139f8052dSShubhrajyoti D mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, 134239f8052dSShubhrajyoti D OMAP2_MCSPI_WAKEUPENABLE_WKEN); 134339f8052dSShubhrajyoti D ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; 1344ca632f55SGrant Likely 1345*89e8b9cbSVignesh R omap2_mcspi_set_mode(master); 1346034d3dc9SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 1347034d3dc9SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 1348ca632f55SGrant Likely return 0; 1349ca632f55SGrant Likely } 1350ca632f55SGrant Likely 135152e9a5bbSTony Lindgren /* 135252e9a5bbSTony Lindgren * When SPI wake up from off-mode, CS is in activate state. If it was in 135352e9a5bbSTony Lindgren * inactive state when driver was suspend, then force it to inactive state at 135452e9a5bbSTony Lindgren * wake up. 135552e9a5bbSTony Lindgren */ 1356ca632f55SGrant Likely static int omap_mcspi_runtime_resume(struct device *dev) 1357ca632f55SGrant Likely { 135852e9a5bbSTony Lindgren struct spi_master *master = dev_get_drvdata(dev); 135952e9a5bbSTony Lindgren struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 136052e9a5bbSTony Lindgren struct omap2_mcspi_regs *ctx = &mcspi->ctx; 136152e9a5bbSTony Lindgren struct omap2_mcspi_cs *cs; 1362ca632f55SGrant Likely 136352e9a5bbSTony Lindgren /* McSPI: context restore */ 136452e9a5bbSTony Lindgren mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); 136552e9a5bbSTony Lindgren mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); 136652e9a5bbSTony Lindgren 136752e9a5bbSTony Lindgren list_for_each_entry(cs, &ctx->cs, node) { 136852e9a5bbSTony Lindgren /* 136952e9a5bbSTony Lindgren * We need to toggle CS state for OMAP take this 137052e9a5bbSTony Lindgren * change in account. 137152e9a5bbSTony Lindgren */ 137252e9a5bbSTony Lindgren if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { 137352e9a5bbSTony Lindgren cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; 137452e9a5bbSTony Lindgren writel_relaxed(cs->chconf0, 137552e9a5bbSTony Lindgren cs->base + OMAP2_MCSPI_CHCONF0); 137652e9a5bbSTony Lindgren cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; 137752e9a5bbSTony Lindgren writel_relaxed(cs->chconf0, 137852e9a5bbSTony Lindgren cs->base + OMAP2_MCSPI_CHCONF0); 137952e9a5bbSTony Lindgren } else { 138052e9a5bbSTony Lindgren writel_relaxed(cs->chconf0, 138152e9a5bbSTony Lindgren cs->base + OMAP2_MCSPI_CHCONF0); 138252e9a5bbSTony Lindgren } 138352e9a5bbSTony Lindgren } 1384ca632f55SGrant Likely 1385ca632f55SGrant Likely return 0; 1386ca632f55SGrant Likely } 1387ca632f55SGrant Likely 1388d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap2_pdata = { 1389d5a80031SBenoit Cousson .regs_offset = 0, 1390d5a80031SBenoit Cousson }; 1391d5a80031SBenoit Cousson 1392d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap4_pdata = { 1393d5a80031SBenoit Cousson .regs_offset = OMAP4_MCSPI_REG_OFFSET, 1394d5a80031SBenoit Cousson }; 1395d5a80031SBenoit Cousson 1396d5a80031SBenoit Cousson static const struct of_device_id omap_mcspi_of_match[] = { 1397d5a80031SBenoit Cousson { 1398d5a80031SBenoit Cousson .compatible = "ti,omap2-mcspi", 1399d5a80031SBenoit Cousson .data = &omap2_pdata, 1400d5a80031SBenoit Cousson }, 1401d5a80031SBenoit Cousson { 1402d5a80031SBenoit Cousson .compatible = "ti,omap4-mcspi", 1403d5a80031SBenoit Cousson .data = &omap4_pdata, 1404d5a80031SBenoit Cousson }, 1405d5a80031SBenoit Cousson { }, 1406d5a80031SBenoit Cousson }; 1407d5a80031SBenoit Cousson MODULE_DEVICE_TABLE(of, omap_mcspi_of_match); 1408ca632f55SGrant Likely 1409fd4a319bSGrant Likely static int omap2_mcspi_probe(struct platform_device *pdev) 1410ca632f55SGrant Likely { 1411ca632f55SGrant Likely struct spi_master *master; 141283a01e72SUwe Kleine-König const struct omap2_mcspi_platform_config *pdata; 1413ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1414ca632f55SGrant Likely struct resource *r; 1415ca632f55SGrant Likely int status = 0, i; 1416d5a80031SBenoit Cousson u32 regs_offset = 0; 1417d5a80031SBenoit Cousson struct device_node *node = pdev->dev.of_node; 1418d5a80031SBenoit Cousson const struct of_device_id *match; 1419ca632f55SGrant Likely 1420*89e8b9cbSVignesh R if (of_property_read_bool(node, "spi-slave")) 1421*89e8b9cbSVignesh R master = spi_alloc_slave(&pdev->dev, sizeof(*mcspi)); 1422*89e8b9cbSVignesh R else 1423*89e8b9cbSVignesh R master = spi_alloc_master(&pdev->dev, sizeof(*mcspi)); 1424*89e8b9cbSVignesh R if (!master) 1425ca632f55SGrant Likely return -ENOMEM; 1426ca632f55SGrant Likely 1427ca632f55SGrant Likely /* the spi->mode bits understood by this driver: */ 1428ca632f55SGrant Likely master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; 142924778be2SStephen Warren master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 1430ca632f55SGrant Likely master->setup = omap2_mcspi_setup; 1431f0278a1aSMark Brown master->auto_runtime_pm = true; 1432468a3208SNeil Armstrong master->prepare_message = omap2_mcspi_prepare_message; 14330ba1870fSFranklin S Cooper Jr master->can_dma = omap2_mcspi_can_dma; 1434b28cb941SMichael Welling master->transfer_one = omap2_mcspi_transfer_one; 1435ddcad7e9SMichael Welling master->set_cs = omap2_mcspi_set_cs; 1436ca632f55SGrant Likely master->cleanup = omap2_mcspi_cleanup; 1437*89e8b9cbSVignesh R master->slave_abort = omap2_mcspi_slave_abort; 1438d5a80031SBenoit Cousson master->dev.of_node = node; 1439aca0924bSAxel Lin master->max_speed_hz = OMAP2_MCSPI_MAX_FREQ; 1440aca0924bSAxel Lin master->min_speed_hz = OMAP2_MCSPI_MAX_FREQ >> 15; 1441d5a80031SBenoit Cousson 144224b5a82cSJingoo Han platform_set_drvdata(pdev, master); 14430384e90bSDaniel Mack 14440384e90bSDaniel Mack mcspi = spi_master_get_devdata(master); 14450384e90bSDaniel Mack mcspi->master = master; 14460384e90bSDaniel Mack 1447d5a80031SBenoit Cousson match = of_match_device(omap_mcspi_of_match, &pdev->dev); 1448d5a80031SBenoit Cousson if (match) { 1449d5a80031SBenoit Cousson u32 num_cs = 1; /* default number of chipselect */ 1450d5a80031SBenoit Cousson pdata = match->data; 1451d5a80031SBenoit Cousson 1452d5a80031SBenoit Cousson of_property_read_u32(node, "ti,spi-num-cs", &num_cs); 1453d5a80031SBenoit Cousson master->num_chipselect = num_cs; 14542cd45179SDaniel Mack if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL)) 14552cd45179SDaniel Mack mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; 1456d5a80031SBenoit Cousson } else { 14578074cf06SJingoo Han pdata = dev_get_platdata(&pdev->dev); 1458ca632f55SGrant Likely master->num_chipselect = pdata->num_cs; 14590384e90bSDaniel Mack mcspi->pin_dir = pdata->pin_dir; 1460d5a80031SBenoit Cousson } 1461d5a80031SBenoit Cousson regs_offset = pdata->regs_offset; 1462ca632f55SGrant Likely 1463ca632f55SGrant Likely r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1464b0ee5605SThierry Reding mcspi->base = devm_ioremap_resource(&pdev->dev, r); 1465b0ee5605SThierry Reding if (IS_ERR(mcspi->base)) { 1466b0ee5605SThierry Reding status = PTR_ERR(mcspi->base); 14671a77b127SShubhrajyoti D goto free_master; 1468ca632f55SGrant Likely } 1469af9e53feSVikram N mcspi->phys = r->start + regs_offset; 1470af9e53feSVikram N mcspi->base += regs_offset; 1471ca632f55SGrant Likely 1472ca632f55SGrant Likely mcspi->dev = &pdev->dev; 1473ca632f55SGrant Likely 14741bd897f8SBenoit Cousson INIT_LIST_HEAD(&mcspi->ctx.cs); 1475ca632f55SGrant Likely 1476a6f936dbSAxel Lin mcspi->dma_channels = devm_kcalloc(&pdev->dev, master->num_chipselect, 1477ca632f55SGrant Likely sizeof(struct omap2_mcspi_dma), 1478ca632f55SGrant Likely GFP_KERNEL); 1479a6f936dbSAxel Lin if (mcspi->dma_channels == NULL) { 1480a6f936dbSAxel Lin status = -ENOMEM; 14811a77b127SShubhrajyoti D goto free_master; 1482a6f936dbSAxel Lin } 1483ca632f55SGrant Likely 1484ca632f55SGrant Likely for (i = 0; i < master->num_chipselect; i++) { 1485b085c612SPeter Ujfalusi sprintf(mcspi->dma_channels[i].dma_rx_ch_name, "rx%d", i); 1486b085c612SPeter Ujfalusi sprintf(mcspi->dma_channels[i].dma_tx_ch_name, "tx%d", i); 1487ca632f55SGrant Likely } 1488ca632f55SGrant Likely 1489*89e8b9cbSVignesh R status = platform_get_irq(pdev, 0); 1490*89e8b9cbSVignesh R if (status == -EPROBE_DEFER) 1491*89e8b9cbSVignesh R goto free_master; 1492*89e8b9cbSVignesh R if (status < 0) { 1493*89e8b9cbSVignesh R dev_err(&pdev->dev, "no irq resource found\n"); 1494*89e8b9cbSVignesh R goto free_master; 1495*89e8b9cbSVignesh R } 1496*89e8b9cbSVignesh R init_completion(&mcspi->txdone); 1497*89e8b9cbSVignesh R status = devm_request_irq(&pdev->dev, status, 1498*89e8b9cbSVignesh R omap2_mcspi_irq_handler, 0, pdev->name, 1499*89e8b9cbSVignesh R mcspi); 1500*89e8b9cbSVignesh R if (status) { 1501*89e8b9cbSVignesh R dev_err(&pdev->dev, "Cannot request IRQ"); 1502*89e8b9cbSVignesh R goto free_master; 1503*89e8b9cbSVignesh R } 1504*89e8b9cbSVignesh R 150527b5284cSShubhrajyoti D pm_runtime_use_autosuspend(&pdev->dev); 150627b5284cSShubhrajyoti D pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); 1507ca632f55SGrant Likely pm_runtime_enable(&pdev->dev); 1508ca632f55SGrant Likely 1509*89e8b9cbSVignesh R status = omap2_mcspi_controller_setup(mcspi); 1510142e07beSWei Yongjun if (status < 0) 151139f1b565SShubhrajyoti D goto disable_pm; 1512ca632f55SGrant Likely 1513*89e8b9cbSVignesh R status = devm_spi_register_controller(&pdev->dev, master); 1514ca632f55SGrant Likely if (status < 0) 151537a2d84aSShubhrajyoti D goto disable_pm; 1516ca632f55SGrant Likely 1517ca632f55SGrant Likely return status; 1518ca632f55SGrant Likely 151939f1b565SShubhrajyoti D disable_pm: 15200e6f357aSTony Lindgren pm_runtime_dont_use_autosuspend(&pdev->dev); 15210e6f357aSTony Lindgren pm_runtime_put_sync(&pdev->dev); 1522751c925cSShubhrajyoti D pm_runtime_disable(&pdev->dev); 152339f1b565SShubhrajyoti D free_master: 152437a2d84aSShubhrajyoti D spi_master_put(master); 1525ca632f55SGrant Likely return status; 1526ca632f55SGrant Likely } 1527ca632f55SGrant Likely 1528fd4a319bSGrant Likely static int omap2_mcspi_remove(struct platform_device *pdev) 1529ca632f55SGrant Likely { 1530a6f936dbSAxel Lin struct spi_master *master = platform_get_drvdata(pdev); 1531a6f936dbSAxel Lin struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 1532ca632f55SGrant Likely 15330e6f357aSTony Lindgren pm_runtime_dont_use_autosuspend(mcspi->dev); 1534a93a2029SShubhrajyoti D pm_runtime_put_sync(mcspi->dev); 1535751c925cSShubhrajyoti D pm_runtime_disable(&pdev->dev); 1536ca632f55SGrant Likely 1537ca632f55SGrant Likely return 0; 1538ca632f55SGrant Likely } 1539ca632f55SGrant Likely 1540ca632f55SGrant Likely /* work with hotplug and coldplug */ 1541ca632f55SGrant Likely MODULE_ALIAS("platform:omap2_mcspi"); 1542ca632f55SGrant Likely 1543ca632f55SGrant Likely #ifdef CONFIG_SUSPEND 15445a686b2cSTony Lindgren static int omap2_mcspi_suspend_noirq(struct device *dev) 1545ca632f55SGrant Likely { 1546beca3655SPascal Huerst return pinctrl_pm_select_sleep_state(dev); 1547beca3655SPascal Huerst } 1548beca3655SPascal Huerst 15495a686b2cSTony Lindgren static int omap2_mcspi_resume_noirq(struct device *dev) 15505a686b2cSTony Lindgren { 15515a686b2cSTony Lindgren struct spi_master *master = dev_get_drvdata(dev); 15525a686b2cSTony Lindgren struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 15535a686b2cSTony Lindgren int error; 15545a686b2cSTony Lindgren 15555a686b2cSTony Lindgren error = pinctrl_pm_select_default_state(dev); 15565a686b2cSTony Lindgren if (error) 15575a686b2cSTony Lindgren dev_warn(mcspi->dev, "%s: failed to set pins: %i\n", 15585a686b2cSTony Lindgren __func__, error); 15595a686b2cSTony Lindgren 15605a686b2cSTony Lindgren return 0; 15615a686b2cSTony Lindgren } 15625a686b2cSTony Lindgren 1563ca632f55SGrant Likely #else 15645a686b2cSTony Lindgren #define omap2_mcspi_suspend_noirq NULL 15655a686b2cSTony Lindgren #define omap2_mcspi_resume_noirq NULL 1566ca632f55SGrant Likely #endif 1567ca632f55SGrant Likely 1568ca632f55SGrant Likely static const struct dev_pm_ops omap2_mcspi_pm_ops = { 15695a686b2cSTony Lindgren .suspend_noirq = omap2_mcspi_suspend_noirq, 15705a686b2cSTony Lindgren .resume_noirq = omap2_mcspi_resume_noirq, 1571ca632f55SGrant Likely .runtime_resume = omap_mcspi_runtime_resume, 1572ca632f55SGrant Likely }; 1573ca632f55SGrant Likely 1574ca632f55SGrant Likely static struct platform_driver omap2_mcspi_driver = { 1575ca632f55SGrant Likely .driver = { 1576ca632f55SGrant Likely .name = "omap2_mcspi", 1577d5a80031SBenoit Cousson .pm = &omap2_mcspi_pm_ops, 1578d5a80031SBenoit Cousson .of_match_table = omap_mcspi_of_match, 1579ca632f55SGrant Likely }, 15807d6b6d83SFelipe Balbi .probe = omap2_mcspi_probe, 1581fd4a319bSGrant Likely .remove = omap2_mcspi_remove, 1582ca632f55SGrant Likely }; 1583ca632f55SGrant Likely 15849fdca9dfSFelipe Balbi module_platform_driver(omap2_mcspi_driver); 1585ca632f55SGrant Likely MODULE_LICENSE("GPL"); 1586