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 * You should have received a copy of the GNU General Public License 19ca632f55SGrant Likely * along with this program; if not, write to the Free Software 20ca632f55SGrant Likely * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21ca632f55SGrant Likely * 22ca632f55SGrant Likely */ 23ca632f55SGrant Likely 24ca632f55SGrant Likely #include <linux/kernel.h> 25ca632f55SGrant Likely #include <linux/init.h> 26ca632f55SGrant Likely #include <linux/interrupt.h> 27ca632f55SGrant Likely #include <linux/module.h> 28ca632f55SGrant Likely #include <linux/device.h> 29ca632f55SGrant Likely #include <linux/delay.h> 30ca632f55SGrant Likely #include <linux/dma-mapping.h> 3153741ed8SRussell King #include <linux/dmaengine.h> 3253741ed8SRussell King #include <linux/omap-dma.h> 33ca632f55SGrant Likely #include <linux/platform_device.h> 34ca632f55SGrant Likely #include <linux/err.h> 35ca632f55SGrant Likely #include <linux/clk.h> 36ca632f55SGrant Likely #include <linux/io.h> 37ca632f55SGrant Likely #include <linux/slab.h> 38ca632f55SGrant Likely #include <linux/pm_runtime.h> 39d5a80031SBenoit Cousson #include <linux/of.h> 40d5a80031SBenoit Cousson #include <linux/of_device.h> 41d33f473dSIllia Smyrnov #include <linux/gcd.h> 42ca632f55SGrant Likely 43ca632f55SGrant Likely #include <linux/spi/spi.h> 44ca632f55SGrant Likely 452203747cSArnd Bergmann #include <linux/platform_data/spi-omap2-mcspi.h> 46ca632f55SGrant Likely 47ca632f55SGrant Likely #define OMAP2_MCSPI_MAX_FREQ 48000000 48d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFODEPTH 64 49d33f473dSIllia Smyrnov #define OMAP2_MCSPI_MAX_FIFOWCNT 0xFFFF 5027b5284cSShubhrajyoti D #define SPI_AUTOSUSPEND_TIMEOUT 2000 51ca632f55SGrant Likely 52ca632f55SGrant Likely #define OMAP2_MCSPI_REVISION 0x00 53ca632f55SGrant Likely #define OMAP2_MCSPI_SYSSTATUS 0x14 54ca632f55SGrant Likely #define OMAP2_MCSPI_IRQSTATUS 0x18 55ca632f55SGrant Likely #define OMAP2_MCSPI_IRQENABLE 0x1c 56ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE 0x20 57ca632f55SGrant Likely #define OMAP2_MCSPI_SYST 0x24 58ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL 0x28 59d33f473dSIllia Smyrnov #define OMAP2_MCSPI_XFERLEVEL 0x7c 60ca632f55SGrant Likely 61ca632f55SGrant Likely /* per-channel banks, 0x14 bytes each, first is: */ 62ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF0 0x2c 63ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT0 0x30 64ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL0 0x34 65ca632f55SGrant Likely #define OMAP2_MCSPI_TX0 0x38 66ca632f55SGrant Likely #define OMAP2_MCSPI_RX0 0x3c 67ca632f55SGrant Likely 68ca632f55SGrant Likely /* per-register bitmasks: */ 69d33f473dSIllia Smyrnov #define OMAP2_MCSPI_IRQSTATUS_EOW BIT(17) 70ca632f55SGrant Likely 71ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_SINGLE BIT(0) 72ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_MS BIT(2) 73ca632f55SGrant Likely #define OMAP2_MCSPI_MODULCTRL_STEST BIT(3) 74ca632f55SGrant Likely 75ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_PHA BIT(0) 76ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_POL BIT(1) 77ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_CLKD_MASK (0x0f << 2) 78ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_EPOL BIT(6) 79ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_WL_MASK (0x1f << 7) 80ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_RX_ONLY BIT(12) 81ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_TX_ONLY BIT(13) 82ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TRM_MASK (0x03 << 12) 83ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAW BIT(14) 84ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DMAR BIT(15) 85ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE0 BIT(16) 86ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_DPE1 BIT(17) 87ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_IS BIT(18) 88ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_TURBO BIT(19) 89ca632f55SGrant Likely #define OMAP2_MCSPI_CHCONF_FORCE BIT(20) 90d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFET BIT(27) 91d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHCONF_FFER BIT(28) 92ca632f55SGrant Likely 93ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_RXS BIT(0) 94ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_TXS BIT(1) 95ca632f55SGrant Likely #define OMAP2_MCSPI_CHSTAT_EOT BIT(2) 96d33f473dSIllia Smyrnov #define OMAP2_MCSPI_CHSTAT_TXFFE BIT(3) 97ca632f55SGrant Likely 98ca632f55SGrant Likely #define OMAP2_MCSPI_CHCTRL_EN BIT(0) 99ca632f55SGrant Likely 100ca632f55SGrant Likely #define OMAP2_MCSPI_WAKEUPENABLE_WKEN BIT(0) 101ca632f55SGrant Likely 102ca632f55SGrant Likely /* We have 2 DMA channels per CS, one for RX and one for TX */ 103ca632f55SGrant Likely struct omap2_mcspi_dma { 10453741ed8SRussell King struct dma_chan *dma_tx; 10553741ed8SRussell King struct dma_chan *dma_rx; 106ca632f55SGrant Likely 107ca632f55SGrant Likely int dma_tx_sync_dev; 108ca632f55SGrant Likely int dma_rx_sync_dev; 109ca632f55SGrant Likely 110ca632f55SGrant Likely struct completion dma_tx_completion; 111ca632f55SGrant Likely struct completion dma_rx_completion; 11274f3aaadSMatt Porter 11374f3aaadSMatt Porter char dma_rx_ch_name[14]; 11474f3aaadSMatt Porter char dma_tx_ch_name[14]; 115ca632f55SGrant Likely }; 116ca632f55SGrant Likely 117ca632f55SGrant Likely /* use PIO for small transfers, avoiding DMA setup/teardown overhead and 118ca632f55SGrant Likely * cache operations; better heuristics consider wordsize and bitrate. 119ca632f55SGrant Likely */ 120ca632f55SGrant Likely #define DMA_MIN_BYTES 160 121ca632f55SGrant Likely 122ca632f55SGrant Likely 1231bd897f8SBenoit Cousson /* 1241bd897f8SBenoit Cousson * Used for context save and restore, structure members to be updated whenever 1251bd897f8SBenoit Cousson * corresponding registers are modified. 1261bd897f8SBenoit Cousson */ 1271bd897f8SBenoit Cousson struct omap2_mcspi_regs { 1281bd897f8SBenoit Cousson u32 modulctrl; 1291bd897f8SBenoit Cousson u32 wakeupenable; 1301bd897f8SBenoit Cousson struct list_head cs; 1311bd897f8SBenoit Cousson }; 1321bd897f8SBenoit Cousson 133ca632f55SGrant Likely struct omap2_mcspi { 134ca632f55SGrant Likely struct spi_master *master; 135ca632f55SGrant Likely /* Virtual base address of the controller */ 136ca632f55SGrant Likely void __iomem *base; 137ca632f55SGrant Likely unsigned long phys; 138ca632f55SGrant Likely /* SPI1 has 4 channels, while SPI2 has 2 */ 139ca632f55SGrant Likely struct omap2_mcspi_dma *dma_channels; 140ca632f55SGrant Likely struct device *dev; 1411bd897f8SBenoit Cousson struct omap2_mcspi_regs ctx; 142d33f473dSIllia Smyrnov int fifo_depth; 1430384e90bSDaniel Mack unsigned int pin_dir:1; 144ca632f55SGrant Likely }; 145ca632f55SGrant Likely 146ca632f55SGrant Likely struct omap2_mcspi_cs { 147ca632f55SGrant Likely void __iomem *base; 148ca632f55SGrant Likely unsigned long phys; 149ca632f55SGrant Likely int word_len; 150ca632f55SGrant Likely struct list_head node; 151ca632f55SGrant Likely /* Context save and restore shadow register */ 152ca632f55SGrant Likely u32 chconf0; 153ca632f55SGrant Likely }; 154ca632f55SGrant Likely 155ca632f55SGrant Likely static inline void mcspi_write_reg(struct spi_master *master, 156ca632f55SGrant Likely int idx, u32 val) 157ca632f55SGrant Likely { 158ca632f55SGrant Likely struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 159ca632f55SGrant Likely 160ca632f55SGrant Likely __raw_writel(val, mcspi->base + idx); 161ca632f55SGrant Likely } 162ca632f55SGrant Likely 163ca632f55SGrant Likely static inline u32 mcspi_read_reg(struct spi_master *master, int idx) 164ca632f55SGrant Likely { 165ca632f55SGrant Likely struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 166ca632f55SGrant Likely 167ca632f55SGrant Likely return __raw_readl(mcspi->base + idx); 168ca632f55SGrant Likely } 169ca632f55SGrant Likely 170ca632f55SGrant Likely static inline void mcspi_write_cs_reg(const struct spi_device *spi, 171ca632f55SGrant Likely int idx, u32 val) 172ca632f55SGrant Likely { 173ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 174ca632f55SGrant Likely 175ca632f55SGrant Likely __raw_writel(val, cs->base + idx); 176ca632f55SGrant Likely } 177ca632f55SGrant Likely 178ca632f55SGrant Likely static inline u32 mcspi_read_cs_reg(const struct spi_device *spi, int idx) 179ca632f55SGrant Likely { 180ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 181ca632f55SGrant Likely 182ca632f55SGrant Likely return __raw_readl(cs->base + idx); 183ca632f55SGrant Likely } 184ca632f55SGrant Likely 185ca632f55SGrant Likely static inline u32 mcspi_cached_chconf0(const struct spi_device *spi) 186ca632f55SGrant Likely { 187ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 188ca632f55SGrant Likely 189ca632f55SGrant Likely return cs->chconf0; 190ca632f55SGrant Likely } 191ca632f55SGrant Likely 192ca632f55SGrant Likely static inline void mcspi_write_chconf0(const struct spi_device *spi, u32 val) 193ca632f55SGrant Likely { 194ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 195ca632f55SGrant Likely 196ca632f55SGrant Likely cs->chconf0 = val; 197ca632f55SGrant Likely mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCONF0, val); 198ca632f55SGrant Likely mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0); 199ca632f55SGrant Likely } 200ca632f55SGrant Likely 20156cd5c15SIllia Smyrnov static inline int mcspi_bytes_per_word(int word_len) 20256cd5c15SIllia Smyrnov { 20356cd5c15SIllia Smyrnov if (word_len <= 8) 20456cd5c15SIllia Smyrnov return 1; 20556cd5c15SIllia Smyrnov else if (word_len <= 16) 20656cd5c15SIllia Smyrnov return 2; 20756cd5c15SIllia Smyrnov else /* word_len <= 32 */ 20856cd5c15SIllia Smyrnov return 4; 20956cd5c15SIllia Smyrnov } 21056cd5c15SIllia Smyrnov 211ca632f55SGrant Likely static void omap2_mcspi_set_dma_req(const struct spi_device *spi, 212ca632f55SGrant Likely int is_read, int enable) 213ca632f55SGrant Likely { 214ca632f55SGrant Likely u32 l, rw; 215ca632f55SGrant Likely 216ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 217ca632f55SGrant Likely 218ca632f55SGrant Likely if (is_read) /* 1 is read, 0 write */ 219ca632f55SGrant Likely rw = OMAP2_MCSPI_CHCONF_DMAR; 220ca632f55SGrant Likely else 221ca632f55SGrant Likely rw = OMAP2_MCSPI_CHCONF_DMAW; 222ca632f55SGrant Likely 223af4e944dSShubhrajyoti D if (enable) 224af4e944dSShubhrajyoti D l |= rw; 225af4e944dSShubhrajyoti D else 226af4e944dSShubhrajyoti D l &= ~rw; 227af4e944dSShubhrajyoti D 228ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 229ca632f55SGrant Likely } 230ca632f55SGrant Likely 231ca632f55SGrant Likely static void omap2_mcspi_set_enable(const struct spi_device *spi, int enable) 232ca632f55SGrant Likely { 233ca632f55SGrant Likely u32 l; 234ca632f55SGrant Likely 235ca632f55SGrant Likely l = enable ? OMAP2_MCSPI_CHCTRL_EN : 0; 236ca632f55SGrant Likely mcspi_write_cs_reg(spi, OMAP2_MCSPI_CHCTRL0, l); 237ca632f55SGrant Likely /* Flash post-writes */ 238ca632f55SGrant Likely mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCTRL0); 239ca632f55SGrant Likely } 240ca632f55SGrant Likely 241ca632f55SGrant Likely static void omap2_mcspi_force_cs(struct spi_device *spi, int cs_active) 242ca632f55SGrant Likely { 243ca632f55SGrant Likely u32 l; 244ca632f55SGrant Likely 245ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 246af4e944dSShubhrajyoti D if (cs_active) 247af4e944dSShubhrajyoti D l |= OMAP2_MCSPI_CHCONF_FORCE; 248af4e944dSShubhrajyoti D else 249af4e944dSShubhrajyoti D l &= ~OMAP2_MCSPI_CHCONF_FORCE; 250af4e944dSShubhrajyoti D 251ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 252ca632f55SGrant Likely } 253ca632f55SGrant Likely 254ca632f55SGrant Likely static void omap2_mcspi_set_master_mode(struct spi_master *master) 255ca632f55SGrant Likely { 2561bd897f8SBenoit Cousson struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 2571bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 258ca632f55SGrant Likely u32 l; 259ca632f55SGrant Likely 2601bd897f8SBenoit Cousson /* 2611bd897f8SBenoit Cousson * Setup when switching from (reset default) slave mode 262ca632f55SGrant Likely * to single-channel master mode 263ca632f55SGrant Likely */ 264ca632f55SGrant Likely l = mcspi_read_reg(master, OMAP2_MCSPI_MODULCTRL); 265af4e944dSShubhrajyoti D l &= ~(OMAP2_MCSPI_MODULCTRL_STEST | OMAP2_MCSPI_MODULCTRL_MS); 266af4e944dSShubhrajyoti D l |= OMAP2_MCSPI_MODULCTRL_SINGLE; 267ca632f55SGrant Likely mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, l); 268ca632f55SGrant Likely 2691bd897f8SBenoit Cousson ctx->modulctrl = l; 270ca632f55SGrant Likely } 271ca632f55SGrant Likely 272d33f473dSIllia Smyrnov static void omap2_mcspi_set_fifo(const struct spi_device *spi, 273d33f473dSIllia Smyrnov struct spi_transfer *t, int enable) 274d33f473dSIllia Smyrnov { 275d33f473dSIllia Smyrnov struct spi_master *master = spi->master; 276d33f473dSIllia Smyrnov struct omap2_mcspi_cs *cs = spi->controller_state; 277d33f473dSIllia Smyrnov struct omap2_mcspi *mcspi; 278d33f473dSIllia Smyrnov unsigned int wcnt; 279d33f473dSIllia Smyrnov int fifo_depth, bytes_per_word; 280d33f473dSIllia Smyrnov u32 chconf, xferlevel; 281d33f473dSIllia Smyrnov 282d33f473dSIllia Smyrnov mcspi = spi_master_get_devdata(master); 283d33f473dSIllia Smyrnov 284d33f473dSIllia Smyrnov chconf = mcspi_cached_chconf0(spi); 285d33f473dSIllia Smyrnov if (enable) { 286d33f473dSIllia Smyrnov bytes_per_word = mcspi_bytes_per_word(cs->word_len); 287d33f473dSIllia Smyrnov if (t->len % bytes_per_word != 0) 288d33f473dSIllia Smyrnov goto disable_fifo; 289d33f473dSIllia Smyrnov 290d33f473dSIllia Smyrnov fifo_depth = gcd(t->len, OMAP2_MCSPI_MAX_FIFODEPTH); 291d33f473dSIllia Smyrnov if (fifo_depth < 2 || fifo_depth % bytes_per_word != 0) 292d33f473dSIllia Smyrnov goto disable_fifo; 293d33f473dSIllia Smyrnov 294d33f473dSIllia Smyrnov wcnt = t->len / bytes_per_word; 295d33f473dSIllia Smyrnov if (wcnt > OMAP2_MCSPI_MAX_FIFOWCNT) 296d33f473dSIllia Smyrnov goto disable_fifo; 297d33f473dSIllia Smyrnov 298d33f473dSIllia Smyrnov xferlevel = wcnt << 16; 299d33f473dSIllia Smyrnov if (t->rx_buf != NULL) { 300d33f473dSIllia Smyrnov chconf |= OMAP2_MCSPI_CHCONF_FFER; 301d33f473dSIllia Smyrnov xferlevel |= (fifo_depth - 1) << 8; 302d33f473dSIllia Smyrnov } else { 303d33f473dSIllia Smyrnov chconf |= OMAP2_MCSPI_CHCONF_FFET; 304d33f473dSIllia Smyrnov xferlevel |= fifo_depth - 1; 305d33f473dSIllia Smyrnov } 306d33f473dSIllia Smyrnov 307d33f473dSIllia Smyrnov mcspi_write_reg(master, OMAP2_MCSPI_XFERLEVEL, xferlevel); 308d33f473dSIllia Smyrnov mcspi_write_chconf0(spi, chconf); 309d33f473dSIllia Smyrnov mcspi->fifo_depth = fifo_depth; 310d33f473dSIllia Smyrnov 311d33f473dSIllia Smyrnov return; 312d33f473dSIllia Smyrnov } 313d33f473dSIllia Smyrnov 314d33f473dSIllia Smyrnov disable_fifo: 315d33f473dSIllia Smyrnov if (t->rx_buf != NULL) 316d33f473dSIllia Smyrnov chconf &= ~OMAP2_MCSPI_CHCONF_FFER; 317d33f473dSIllia Smyrnov else 318d33f473dSIllia Smyrnov chconf &= ~OMAP2_MCSPI_CHCONF_FFET; 319d33f473dSIllia Smyrnov 320d33f473dSIllia Smyrnov mcspi_write_chconf0(spi, chconf); 321d33f473dSIllia Smyrnov mcspi->fifo_depth = 0; 322d33f473dSIllia Smyrnov } 323d33f473dSIllia Smyrnov 324ca632f55SGrant Likely static void omap2_mcspi_restore_ctx(struct omap2_mcspi *mcspi) 325ca632f55SGrant Likely { 3261bd897f8SBenoit Cousson struct spi_master *spi_cntrl = mcspi->master; 3271bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 328ca632f55SGrant Likely struct omap2_mcspi_cs *cs; 329ca632f55SGrant Likely 330ca632f55SGrant Likely /* McSPI: context restore */ 3311bd897f8SBenoit Cousson mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_MODULCTRL, ctx->modulctrl); 3321bd897f8SBenoit Cousson mcspi_write_reg(spi_cntrl, OMAP2_MCSPI_WAKEUPENABLE, ctx->wakeupenable); 333ca632f55SGrant Likely 3341bd897f8SBenoit Cousson list_for_each_entry(cs, &ctx->cs, node) 335ca632f55SGrant Likely __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); 336ca632f55SGrant Likely } 337ca632f55SGrant Likely 3385fda88f5SShubhrajyoti D static int omap2_prepare_transfer(struct spi_master *master) 3395fda88f5SShubhrajyoti D { 3405fda88f5SShubhrajyoti D struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 3415fda88f5SShubhrajyoti D 3425fda88f5SShubhrajyoti D pm_runtime_get_sync(mcspi->dev); 3435fda88f5SShubhrajyoti D return 0; 3445fda88f5SShubhrajyoti D } 3455fda88f5SShubhrajyoti D 3465fda88f5SShubhrajyoti D static int omap2_unprepare_transfer(struct spi_master *master) 3475fda88f5SShubhrajyoti D { 3485fda88f5SShubhrajyoti D struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 3495fda88f5SShubhrajyoti D 3505fda88f5SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 3515fda88f5SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 3525fda88f5SShubhrajyoti D return 0; 3535fda88f5SShubhrajyoti D } 3545fda88f5SShubhrajyoti D 355ca632f55SGrant Likely static int mcspi_wait_for_reg_bit(void __iomem *reg, unsigned long bit) 356ca632f55SGrant Likely { 357ca632f55SGrant Likely unsigned long timeout; 358ca632f55SGrant Likely 359ca632f55SGrant Likely timeout = jiffies + msecs_to_jiffies(1000); 360ca632f55SGrant Likely while (!(__raw_readl(reg) & bit)) { 361ff23fa3bSSebastian Andrzej Siewior if (time_after(jiffies, timeout)) { 362ff23fa3bSSebastian Andrzej Siewior if (!(__raw_readl(reg) & bit)) 363ff23fa3bSSebastian Andrzej Siewior return -ETIMEDOUT; 364ff23fa3bSSebastian Andrzej Siewior else 365ff23fa3bSSebastian Andrzej Siewior return 0; 366ff23fa3bSSebastian Andrzej Siewior } 367ca632f55SGrant Likely cpu_relax(); 368ca632f55SGrant Likely } 369ca632f55SGrant Likely return 0; 370ca632f55SGrant Likely } 371ca632f55SGrant Likely 37253741ed8SRussell King static void omap2_mcspi_rx_callback(void *data) 37353741ed8SRussell King { 37453741ed8SRussell King struct spi_device *spi = data; 37553741ed8SRussell King struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 37653741ed8SRussell King struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 37753741ed8SRussell King 37853741ed8SRussell King /* We must disable the DMA RX request */ 37953741ed8SRussell King omap2_mcspi_set_dma_req(spi, 1, 0); 380830379e0SFelipe Balbi 381830379e0SFelipe Balbi complete(&mcspi_dma->dma_rx_completion); 38253741ed8SRussell King } 38353741ed8SRussell King 38453741ed8SRussell King static void omap2_mcspi_tx_callback(void *data) 38553741ed8SRussell King { 38653741ed8SRussell King struct spi_device *spi = data; 38753741ed8SRussell King struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 38853741ed8SRussell King struct omap2_mcspi_dma *mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 38953741ed8SRussell King 39053741ed8SRussell King /* We must disable the DMA TX request */ 39153741ed8SRussell King omap2_mcspi_set_dma_req(spi, 0, 0); 392830379e0SFelipe Balbi 393830379e0SFelipe Balbi complete(&mcspi_dma->dma_tx_completion); 39453741ed8SRussell King } 39553741ed8SRussell King 396d7b4394eSShubhrajyoti D static void omap2_mcspi_tx_dma(struct spi_device *spi, 397d7b4394eSShubhrajyoti D struct spi_transfer *xfer, 398d7b4394eSShubhrajyoti D struct dma_slave_config cfg) 399ca632f55SGrant Likely { 400ca632f55SGrant Likely struct omap2_mcspi *mcspi; 401ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 4028c7494a5SRussell King unsigned int count; 403ca632f55SGrant Likely 404ca632f55SGrant Likely mcspi = spi_master_get_devdata(spi->master); 405ca632f55SGrant Likely mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 406d7b4394eSShubhrajyoti D count = xfer->len; 407ca632f55SGrant Likely 408d7b4394eSShubhrajyoti D if (mcspi_dma->dma_tx) { 40953741ed8SRussell King struct dma_async_tx_descriptor *tx; 41053741ed8SRussell King struct scatterlist sg; 41153741ed8SRussell King 41253741ed8SRussell King dmaengine_slave_config(mcspi_dma->dma_tx, &cfg); 41353741ed8SRussell King 41453741ed8SRussell King sg_init_table(&sg, 1); 41553741ed8SRussell King sg_dma_address(&sg) = xfer->tx_dma; 41653741ed8SRussell King sg_dma_len(&sg) = xfer->len; 41753741ed8SRussell King 41853741ed8SRussell King tx = dmaengine_prep_slave_sg(mcspi_dma->dma_tx, &sg, 1, 41953741ed8SRussell King DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 42053741ed8SRussell King if (tx) { 42153741ed8SRussell King tx->callback = omap2_mcspi_tx_callback; 42253741ed8SRussell King tx->callback_param = spi; 42353741ed8SRussell King dmaengine_submit(tx); 42453741ed8SRussell King } else { 42553741ed8SRussell King /* FIXME: fall back to PIO? */ 42653741ed8SRussell King } 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 } 432ca632f55SGrant Likely 433d7b4394eSShubhrajyoti D static unsigned 434d7b4394eSShubhrajyoti D omap2_mcspi_rx_dma(struct spi_device *spi, struct spi_transfer *xfer, 435d7b4394eSShubhrajyoti D struct dma_slave_config cfg, 436d7b4394eSShubhrajyoti D unsigned es) 437d7b4394eSShubhrajyoti D { 438d7b4394eSShubhrajyoti D struct omap2_mcspi *mcspi; 439d7b4394eSShubhrajyoti D struct omap2_mcspi_dma *mcspi_dma; 440d33f473dSIllia Smyrnov unsigned int count, dma_count; 441d7b4394eSShubhrajyoti D u32 l; 442d7b4394eSShubhrajyoti D int elements = 0; 443d7b4394eSShubhrajyoti D int word_len, element_count; 444d7b4394eSShubhrajyoti D struct omap2_mcspi_cs *cs = spi->controller_state; 445d7b4394eSShubhrajyoti D mcspi = spi_master_get_devdata(spi->master); 446d7b4394eSShubhrajyoti D mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 447d7b4394eSShubhrajyoti D count = xfer->len; 448d33f473dSIllia Smyrnov dma_count = xfer->len; 449d33f473dSIllia Smyrnov 450d33f473dSIllia Smyrnov if (mcspi->fifo_depth == 0) 451d33f473dSIllia Smyrnov dma_count -= es; 452d33f473dSIllia Smyrnov 453d7b4394eSShubhrajyoti D word_len = cs->word_len; 454d7b4394eSShubhrajyoti D l = mcspi_cached_chconf0(spi); 455d7b4394eSShubhrajyoti D 456d7b4394eSShubhrajyoti D if (word_len <= 8) 457d7b4394eSShubhrajyoti D element_count = count; 458d7b4394eSShubhrajyoti D else if (word_len <= 16) 459d7b4394eSShubhrajyoti D element_count = count >> 1; 460d7b4394eSShubhrajyoti D else /* word_len <= 32 */ 461d7b4394eSShubhrajyoti D element_count = count >> 2; 462d7b4394eSShubhrajyoti D 463d7b4394eSShubhrajyoti D if (mcspi_dma->dma_rx) { 464d7b4394eSShubhrajyoti D struct dma_async_tx_descriptor *tx; 465d7b4394eSShubhrajyoti D struct scatterlist sg; 466d7b4394eSShubhrajyoti D 467d7b4394eSShubhrajyoti D dmaengine_slave_config(mcspi_dma->dma_rx, &cfg); 468d7b4394eSShubhrajyoti D 469d33f473dSIllia Smyrnov if ((l & OMAP2_MCSPI_CHCONF_TURBO) && mcspi->fifo_depth == 0) 470d33f473dSIllia Smyrnov dma_count -= es; 471d7b4394eSShubhrajyoti D 472d7b4394eSShubhrajyoti D sg_init_table(&sg, 1); 473d7b4394eSShubhrajyoti D sg_dma_address(&sg) = xfer->rx_dma; 474d33f473dSIllia Smyrnov sg_dma_len(&sg) = dma_count; 475d7b4394eSShubhrajyoti D 476d7b4394eSShubhrajyoti D tx = dmaengine_prep_slave_sg(mcspi_dma->dma_rx, &sg, 1, 477d7b4394eSShubhrajyoti D DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | 478d7b4394eSShubhrajyoti D DMA_CTRL_ACK); 479d7b4394eSShubhrajyoti D if (tx) { 480d7b4394eSShubhrajyoti D tx->callback = omap2_mcspi_rx_callback; 481d7b4394eSShubhrajyoti D tx->callback_param = spi; 482d7b4394eSShubhrajyoti D dmaengine_submit(tx); 483d7b4394eSShubhrajyoti D } else { 484d7b4394eSShubhrajyoti D /* FIXME: fall back to PIO? */ 485d7b4394eSShubhrajyoti D } 486d7b4394eSShubhrajyoti D } 487d7b4394eSShubhrajyoti D 488d7b4394eSShubhrajyoti D dma_async_issue_pending(mcspi_dma->dma_rx); 489d7b4394eSShubhrajyoti D omap2_mcspi_set_dma_req(spi, 1, 1); 490d7b4394eSShubhrajyoti D 491ca632f55SGrant Likely wait_for_completion(&mcspi_dma->dma_rx_completion); 492a3ce9a80SShubhrajyoti D dma_unmap_single(mcspi->dev, xfer->rx_dma, count, 493a3ce9a80SShubhrajyoti D DMA_FROM_DEVICE); 494d33f473dSIllia Smyrnov 495d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) 496d33f473dSIllia Smyrnov return count; 497d33f473dSIllia Smyrnov 498ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 499ca632f55SGrant Likely 50053741ed8SRussell King elements = element_count - 1; 50153741ed8SRussell King 502ca632f55SGrant Likely if (l & OMAP2_MCSPI_CHCONF_TURBO) { 50353741ed8SRussell King elements--; 504ca632f55SGrant Likely 505ca632f55SGrant Likely if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) 506ca632f55SGrant Likely & OMAP2_MCSPI_CHSTAT_RXS)) { 507ca632f55SGrant Likely u32 w; 508ca632f55SGrant Likely 509ca632f55SGrant Likely w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); 510ca632f55SGrant Likely if (word_len <= 8) 511ca632f55SGrant Likely ((u8 *)xfer->rx_buf)[elements++] = w; 512ca632f55SGrant Likely else if (word_len <= 16) 513ca632f55SGrant Likely ((u16 *)xfer->rx_buf)[elements++] = w; 514ca632f55SGrant Likely else /* word_len <= 32 */ 515ca632f55SGrant Likely ((u32 *)xfer->rx_buf)[elements++] = w; 516ca632f55SGrant Likely } else { 51756cd5c15SIllia Smyrnov int bytes_per_word = mcspi_bytes_per_word(word_len); 518d7b4394eSShubhrajyoti D dev_err(&spi->dev, "DMA RX penultimate word empty"); 51956cd5c15SIllia Smyrnov count -= (bytes_per_word << 1); 520ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 521ca632f55SGrant Likely return count; 522ca632f55SGrant Likely } 523ca632f55SGrant Likely } 524ca632f55SGrant Likely if (likely(mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHSTAT0) 525ca632f55SGrant Likely & OMAP2_MCSPI_CHSTAT_RXS)) { 526ca632f55SGrant Likely u32 w; 527ca632f55SGrant Likely 528ca632f55SGrant Likely w = mcspi_read_cs_reg(spi, OMAP2_MCSPI_RX0); 529ca632f55SGrant Likely if (word_len <= 8) 530ca632f55SGrant Likely ((u8 *)xfer->rx_buf)[elements] = w; 531ca632f55SGrant Likely else if (word_len <= 16) 532ca632f55SGrant Likely ((u16 *)xfer->rx_buf)[elements] = w; 533ca632f55SGrant Likely else /* word_len <= 32 */ 534ca632f55SGrant Likely ((u32 *)xfer->rx_buf)[elements] = w; 535ca632f55SGrant Likely } else { 536ca632f55SGrant Likely dev_err(&spi->dev, "DMA RX last word empty"); 53756cd5c15SIllia Smyrnov count -= mcspi_bytes_per_word(word_len); 538ca632f55SGrant Likely } 539ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 540d7b4394eSShubhrajyoti D return count; 541ca632f55SGrant Likely } 542d7b4394eSShubhrajyoti D 543d7b4394eSShubhrajyoti D static unsigned 544d7b4394eSShubhrajyoti D omap2_mcspi_txrx_dma(struct spi_device *spi, struct spi_transfer *xfer) 545d7b4394eSShubhrajyoti D { 546d7b4394eSShubhrajyoti D struct omap2_mcspi *mcspi; 547d7b4394eSShubhrajyoti D struct omap2_mcspi_cs *cs = spi->controller_state; 548d7b4394eSShubhrajyoti D struct omap2_mcspi_dma *mcspi_dma; 549d7b4394eSShubhrajyoti D unsigned int count; 550d7b4394eSShubhrajyoti D u32 l; 551d7b4394eSShubhrajyoti D u8 *rx; 552d7b4394eSShubhrajyoti D const u8 *tx; 553d7b4394eSShubhrajyoti D struct dma_slave_config cfg; 554d7b4394eSShubhrajyoti D enum dma_slave_buswidth width; 555d7b4394eSShubhrajyoti D unsigned es; 556d33f473dSIllia Smyrnov u32 burst; 557e47a682aSShubhrajyoti D void __iomem *chstat_reg; 558d33f473dSIllia Smyrnov void __iomem *irqstat_reg; 559d33f473dSIllia Smyrnov int wait_res; 560d7b4394eSShubhrajyoti D 561d7b4394eSShubhrajyoti D mcspi = spi_master_get_devdata(spi->master); 562d7b4394eSShubhrajyoti D mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 563d7b4394eSShubhrajyoti D l = mcspi_cached_chconf0(spi); 564d7b4394eSShubhrajyoti D 565d7b4394eSShubhrajyoti D 566d7b4394eSShubhrajyoti D if (cs->word_len <= 8) { 567d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_1_BYTE; 568d7b4394eSShubhrajyoti D es = 1; 569d7b4394eSShubhrajyoti D } else if (cs->word_len <= 16) { 570d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_2_BYTES; 571d7b4394eSShubhrajyoti D es = 2; 572d7b4394eSShubhrajyoti D } else { 573d7b4394eSShubhrajyoti D width = DMA_SLAVE_BUSWIDTH_4_BYTES; 574d7b4394eSShubhrajyoti D es = 4; 575d7b4394eSShubhrajyoti D } 576d7b4394eSShubhrajyoti D 577d33f473dSIllia Smyrnov count = xfer->len; 578d33f473dSIllia Smyrnov burst = 1; 579d33f473dSIllia Smyrnov 580d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) { 581d33f473dSIllia Smyrnov if (count > mcspi->fifo_depth) 582d33f473dSIllia Smyrnov burst = mcspi->fifo_depth / es; 583d33f473dSIllia Smyrnov else 584d33f473dSIllia Smyrnov burst = count / es; 585d33f473dSIllia Smyrnov } 586d33f473dSIllia Smyrnov 587d7b4394eSShubhrajyoti D memset(&cfg, 0, sizeof(cfg)); 588d7b4394eSShubhrajyoti D cfg.src_addr = cs->phys + OMAP2_MCSPI_RX0; 589d7b4394eSShubhrajyoti D cfg.dst_addr = cs->phys + OMAP2_MCSPI_TX0; 590d7b4394eSShubhrajyoti D cfg.src_addr_width = width; 591d7b4394eSShubhrajyoti D cfg.dst_addr_width = width; 592d33f473dSIllia Smyrnov cfg.src_maxburst = burst; 593d33f473dSIllia Smyrnov cfg.dst_maxburst = burst; 594d7b4394eSShubhrajyoti D 595d7b4394eSShubhrajyoti D rx = xfer->rx_buf; 596d7b4394eSShubhrajyoti D tx = xfer->tx_buf; 597d7b4394eSShubhrajyoti D 598d7b4394eSShubhrajyoti D if (tx != NULL) 599d7b4394eSShubhrajyoti D omap2_mcspi_tx_dma(spi, xfer, cfg); 600d7b4394eSShubhrajyoti D 601d7b4394eSShubhrajyoti D if (rx != NULL) 602e47a682aSShubhrajyoti D count = omap2_mcspi_rx_dma(spi, xfer, cfg, es); 603d7b4394eSShubhrajyoti D 604e47a682aSShubhrajyoti D if (tx != NULL) { 605e47a682aSShubhrajyoti D wait_for_completion(&mcspi_dma->dma_tx_completion); 606e47a682aSShubhrajyoti D dma_unmap_single(mcspi->dev, xfer->tx_dma, xfer->len, 607e47a682aSShubhrajyoti D DMA_TO_DEVICE); 608e47a682aSShubhrajyoti D 609d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) { 610d33f473dSIllia Smyrnov irqstat_reg = mcspi->base + OMAP2_MCSPI_IRQSTATUS; 611d33f473dSIllia Smyrnov 612d33f473dSIllia Smyrnov if (mcspi_wait_for_reg_bit(irqstat_reg, 613d33f473dSIllia Smyrnov OMAP2_MCSPI_IRQSTATUS_EOW) < 0) 614d33f473dSIllia Smyrnov dev_err(&spi->dev, "EOW timed out\n"); 615d33f473dSIllia Smyrnov 616d33f473dSIllia Smyrnov mcspi_write_reg(mcspi->master, OMAP2_MCSPI_IRQSTATUS, 617d33f473dSIllia Smyrnov OMAP2_MCSPI_IRQSTATUS_EOW); 618d33f473dSIllia Smyrnov } 619d33f473dSIllia Smyrnov 620e47a682aSShubhrajyoti D /* for TX_ONLY mode, be sure all words have shifted out */ 621e47a682aSShubhrajyoti D if (rx == NULL) { 622d33f473dSIllia Smyrnov chstat_reg = cs->base + OMAP2_MCSPI_CHSTAT0; 623d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) { 624d33f473dSIllia Smyrnov wait_res = mcspi_wait_for_reg_bit(chstat_reg, 625d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_TXFFE); 626d33f473dSIllia Smyrnov if (wait_res < 0) 627d33f473dSIllia Smyrnov dev_err(&spi->dev, "TXFFE timed out\n"); 628d33f473dSIllia Smyrnov } else { 629d33f473dSIllia Smyrnov wait_res = mcspi_wait_for_reg_bit(chstat_reg, 630d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_TXS); 631d33f473dSIllia Smyrnov if (wait_res < 0) 632e47a682aSShubhrajyoti D dev_err(&spi->dev, "TXS timed out\n"); 633d33f473dSIllia Smyrnov } 634d33f473dSIllia Smyrnov if (wait_res >= 0 && 635d33f473dSIllia Smyrnov (mcspi_wait_for_reg_bit(chstat_reg, 636d33f473dSIllia Smyrnov OMAP2_MCSPI_CHSTAT_EOT) < 0)) 637e47a682aSShubhrajyoti D dev_err(&spi->dev, "EOT timed out\n"); 638e47a682aSShubhrajyoti D } 639e47a682aSShubhrajyoti D } 640ca632f55SGrant Likely return count; 641ca632f55SGrant Likely } 642ca632f55SGrant Likely 643ca632f55SGrant Likely static unsigned 644ca632f55SGrant Likely omap2_mcspi_txrx_pio(struct spi_device *spi, struct spi_transfer *xfer) 645ca632f55SGrant Likely { 646ca632f55SGrant Likely struct omap2_mcspi *mcspi; 647ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 648ca632f55SGrant Likely unsigned int count, c; 649ca632f55SGrant Likely u32 l; 650ca632f55SGrant Likely void __iomem *base = cs->base; 651ca632f55SGrant Likely void __iomem *tx_reg; 652ca632f55SGrant Likely void __iomem *rx_reg; 653ca632f55SGrant Likely void __iomem *chstat_reg; 654ca632f55SGrant Likely int word_len; 655ca632f55SGrant Likely 656ca632f55SGrant Likely mcspi = spi_master_get_devdata(spi->master); 657ca632f55SGrant Likely count = xfer->len; 658ca632f55SGrant Likely c = count; 659ca632f55SGrant Likely word_len = cs->word_len; 660ca632f55SGrant Likely 661ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 662ca632f55SGrant Likely 663ca632f55SGrant Likely /* We store the pre-calculated register addresses on stack to speed 664ca632f55SGrant Likely * up the transfer loop. */ 665ca632f55SGrant Likely tx_reg = base + OMAP2_MCSPI_TX0; 666ca632f55SGrant Likely rx_reg = base + OMAP2_MCSPI_RX0; 667ca632f55SGrant Likely chstat_reg = base + OMAP2_MCSPI_CHSTAT0; 668ca632f55SGrant Likely 669ca632f55SGrant Likely if (c < (word_len>>3)) 670ca632f55SGrant Likely return 0; 671ca632f55SGrant Likely 672ca632f55SGrant Likely if (word_len <= 8) { 673ca632f55SGrant Likely u8 *rx; 674ca632f55SGrant Likely const u8 *tx; 675ca632f55SGrant Likely 676ca632f55SGrant Likely rx = xfer->rx_buf; 677ca632f55SGrant Likely tx = xfer->tx_buf; 678ca632f55SGrant Likely 679ca632f55SGrant Likely do { 680ca632f55SGrant Likely c -= 1; 681ca632f55SGrant Likely if (tx != NULL) { 682ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 683ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 684ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 685ca632f55SGrant Likely goto out; 686ca632f55SGrant Likely } 687ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %02x\n", 688ca632f55SGrant Likely word_len, *tx); 689ca632f55SGrant Likely __raw_writel(*tx++, tx_reg); 690ca632f55SGrant Likely } 691ca632f55SGrant Likely if (rx != NULL) { 692ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 693ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 694ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 695ca632f55SGrant Likely goto out; 696ca632f55SGrant Likely } 697ca632f55SGrant Likely 698ca632f55SGrant Likely if (c == 1 && tx == NULL && 699ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 700ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 701ca632f55SGrant Likely *rx++ = __raw_readl(rx_reg); 702ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %02x\n", 703ca632f55SGrant Likely word_len, *(rx - 1)); 704ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 705ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 706ca632f55SGrant Likely dev_err(&spi->dev, 707ca632f55SGrant Likely "RXS timed out\n"); 708ca632f55SGrant Likely goto out; 709ca632f55SGrant Likely } 710ca632f55SGrant Likely c = 0; 711ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 712ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 713ca632f55SGrant Likely } 714ca632f55SGrant Likely 715ca632f55SGrant Likely *rx++ = __raw_readl(rx_reg); 716ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %02x\n", 717ca632f55SGrant Likely word_len, *(rx - 1)); 718ca632f55SGrant Likely } 719ca632f55SGrant Likely } while (c); 720ca632f55SGrant Likely } else if (word_len <= 16) { 721ca632f55SGrant Likely u16 *rx; 722ca632f55SGrant Likely const u16 *tx; 723ca632f55SGrant Likely 724ca632f55SGrant Likely rx = xfer->rx_buf; 725ca632f55SGrant Likely tx = xfer->tx_buf; 726ca632f55SGrant Likely do { 727ca632f55SGrant Likely c -= 2; 728ca632f55SGrant Likely if (tx != NULL) { 729ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 730ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 731ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 732ca632f55SGrant Likely goto out; 733ca632f55SGrant Likely } 734ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %04x\n", 735ca632f55SGrant Likely word_len, *tx); 736ca632f55SGrant Likely __raw_writel(*tx++, tx_reg); 737ca632f55SGrant Likely } 738ca632f55SGrant Likely if (rx != NULL) { 739ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 740ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 741ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 742ca632f55SGrant Likely goto out; 743ca632f55SGrant Likely } 744ca632f55SGrant Likely 745ca632f55SGrant Likely if (c == 2 && tx == NULL && 746ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 747ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 748ca632f55SGrant Likely *rx++ = __raw_readl(rx_reg); 749ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %04x\n", 750ca632f55SGrant Likely word_len, *(rx - 1)); 751ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 752ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 753ca632f55SGrant Likely dev_err(&spi->dev, 754ca632f55SGrant Likely "RXS timed out\n"); 755ca632f55SGrant Likely goto out; 756ca632f55SGrant Likely } 757ca632f55SGrant Likely c = 0; 758ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 759ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 760ca632f55SGrant Likely } 761ca632f55SGrant Likely 762ca632f55SGrant Likely *rx++ = __raw_readl(rx_reg); 763ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %04x\n", 764ca632f55SGrant Likely word_len, *(rx - 1)); 765ca632f55SGrant Likely } 766ca632f55SGrant Likely } while (c >= 2); 767ca632f55SGrant Likely } else if (word_len <= 32) { 768ca632f55SGrant Likely u32 *rx; 769ca632f55SGrant Likely const u32 *tx; 770ca632f55SGrant Likely 771ca632f55SGrant Likely rx = xfer->rx_buf; 772ca632f55SGrant Likely tx = xfer->tx_buf; 773ca632f55SGrant Likely do { 774ca632f55SGrant Likely c -= 4; 775ca632f55SGrant Likely if (tx != NULL) { 776ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 777ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 778ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 779ca632f55SGrant Likely goto out; 780ca632f55SGrant Likely } 781ca632f55SGrant Likely dev_vdbg(&spi->dev, "write-%d %08x\n", 782ca632f55SGrant Likely word_len, *tx); 783ca632f55SGrant Likely __raw_writel(*tx++, tx_reg); 784ca632f55SGrant Likely } 785ca632f55SGrant Likely if (rx != NULL) { 786ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 787ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 788ca632f55SGrant Likely dev_err(&spi->dev, "RXS timed out\n"); 789ca632f55SGrant Likely goto out; 790ca632f55SGrant Likely } 791ca632f55SGrant Likely 792ca632f55SGrant Likely if (c == 4 && tx == NULL && 793ca632f55SGrant Likely (l & OMAP2_MCSPI_CHCONF_TURBO)) { 794ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 795ca632f55SGrant Likely *rx++ = __raw_readl(rx_reg); 796ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %08x\n", 797ca632f55SGrant Likely word_len, *(rx - 1)); 798ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 799ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_RXS) < 0) { 800ca632f55SGrant Likely dev_err(&spi->dev, 801ca632f55SGrant Likely "RXS timed out\n"); 802ca632f55SGrant Likely goto out; 803ca632f55SGrant Likely } 804ca632f55SGrant Likely c = 0; 805ca632f55SGrant Likely } else if (c == 0 && tx == NULL) { 806ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 807ca632f55SGrant Likely } 808ca632f55SGrant Likely 809ca632f55SGrant Likely *rx++ = __raw_readl(rx_reg); 810ca632f55SGrant Likely dev_vdbg(&spi->dev, "read-%d %08x\n", 811ca632f55SGrant Likely word_len, *(rx - 1)); 812ca632f55SGrant Likely } 813ca632f55SGrant Likely } while (c >= 4); 814ca632f55SGrant Likely } 815ca632f55SGrant Likely 816ca632f55SGrant Likely /* for TX_ONLY mode, be sure all words have shifted out */ 817ca632f55SGrant Likely if (xfer->rx_buf == NULL) { 818ca632f55SGrant Likely if (mcspi_wait_for_reg_bit(chstat_reg, 819ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_TXS) < 0) { 820ca632f55SGrant Likely dev_err(&spi->dev, "TXS timed out\n"); 821ca632f55SGrant Likely } else if (mcspi_wait_for_reg_bit(chstat_reg, 822ca632f55SGrant Likely OMAP2_MCSPI_CHSTAT_EOT) < 0) 823ca632f55SGrant Likely dev_err(&spi->dev, "EOT timed out\n"); 824ca632f55SGrant Likely 825ca632f55SGrant Likely /* disable chan to purge rx datas received in TX_ONLY transfer, 826ca632f55SGrant Likely * otherwise these rx datas will affect the direct following 827ca632f55SGrant Likely * RX_ONLY transfer. 828ca632f55SGrant Likely */ 829ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 830ca632f55SGrant Likely } 831ca632f55SGrant Likely out: 832ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 1); 833ca632f55SGrant Likely return count - c; 834ca632f55SGrant Likely } 835ca632f55SGrant Likely 836ca632f55SGrant Likely static u32 omap2_mcspi_calc_divisor(u32 speed_hz) 837ca632f55SGrant Likely { 838ca632f55SGrant Likely u32 div; 839ca632f55SGrant Likely 840ca632f55SGrant Likely for (div = 0; div < 15; div++) 841ca632f55SGrant Likely if (speed_hz >= (OMAP2_MCSPI_MAX_FREQ >> div)) 842ca632f55SGrant Likely return div; 843ca632f55SGrant Likely 844ca632f55SGrant Likely return 15; 845ca632f55SGrant Likely } 846ca632f55SGrant Likely 847ca632f55SGrant Likely /* called only when no transfer is active to this device */ 848ca632f55SGrant Likely static int omap2_mcspi_setup_transfer(struct spi_device *spi, 849ca632f55SGrant Likely struct spi_transfer *t) 850ca632f55SGrant Likely { 851ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 852ca632f55SGrant Likely struct omap2_mcspi *mcspi; 853ca632f55SGrant Likely struct spi_master *spi_cntrl; 854ca632f55SGrant Likely u32 l = 0, div = 0; 855ca632f55SGrant Likely u8 word_len = spi->bits_per_word; 856ca632f55SGrant Likely u32 speed_hz = spi->max_speed_hz; 857ca632f55SGrant Likely 858ca632f55SGrant Likely mcspi = spi_master_get_devdata(spi->master); 859ca632f55SGrant Likely spi_cntrl = mcspi->master; 860ca632f55SGrant Likely 861ca632f55SGrant Likely if (t != NULL && t->bits_per_word) 862ca632f55SGrant Likely word_len = t->bits_per_word; 863ca632f55SGrant Likely 864ca632f55SGrant Likely cs->word_len = word_len; 865ca632f55SGrant Likely 866ca632f55SGrant Likely if (t && t->speed_hz) 867ca632f55SGrant Likely speed_hz = t->speed_hz; 868ca632f55SGrant Likely 869ca632f55SGrant Likely speed_hz = min_t(u32, speed_hz, OMAP2_MCSPI_MAX_FREQ); 870ca632f55SGrant Likely div = omap2_mcspi_calc_divisor(speed_hz); 871ca632f55SGrant Likely 872ca632f55SGrant Likely l = mcspi_cached_chconf0(spi); 873ca632f55SGrant Likely 874ca632f55SGrant Likely /* standard 4-wire master mode: SCK, MOSI/out, MISO/in, nCS 875ca632f55SGrant Likely * REVISIT: this controller could support SPI_3WIRE mode. 876ca632f55SGrant Likely */ 8772cd45179SDaniel Mack if (mcspi->pin_dir == MCSPI_PINDIR_D0_IN_D1_OUT) { 8780384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_IS; 8790384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_DPE1; 880ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_DPE0; 8810384e90bSDaniel Mack } else { 8820384e90bSDaniel Mack l |= OMAP2_MCSPI_CHCONF_IS; 8830384e90bSDaniel Mack l |= OMAP2_MCSPI_CHCONF_DPE1; 8840384e90bSDaniel Mack l &= ~OMAP2_MCSPI_CHCONF_DPE0; 8850384e90bSDaniel Mack } 886ca632f55SGrant Likely 887ca632f55SGrant Likely /* wordlength */ 888ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_WL_MASK; 889ca632f55SGrant Likely l |= (word_len - 1) << 7; 890ca632f55SGrant Likely 891ca632f55SGrant Likely /* set chipselect polarity; manage with FORCE */ 892ca632f55SGrant Likely if (!(spi->mode & SPI_CS_HIGH)) 893ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_EPOL; /* active-low; normal */ 894ca632f55SGrant Likely else 895ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_EPOL; 896ca632f55SGrant Likely 897ca632f55SGrant Likely /* set clock divisor */ 898ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_CLKD_MASK; 899ca632f55SGrant Likely l |= div << 2; 900ca632f55SGrant Likely 901ca632f55SGrant Likely /* set SPI mode 0..3 */ 902ca632f55SGrant Likely if (spi->mode & SPI_CPOL) 903ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_POL; 904ca632f55SGrant Likely else 905ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_POL; 906ca632f55SGrant Likely if (spi->mode & SPI_CPHA) 907ca632f55SGrant Likely l |= OMAP2_MCSPI_CHCONF_PHA; 908ca632f55SGrant Likely else 909ca632f55SGrant Likely l &= ~OMAP2_MCSPI_CHCONF_PHA; 910ca632f55SGrant Likely 911ca632f55SGrant Likely mcspi_write_chconf0(spi, l); 912ca632f55SGrant Likely 913ca632f55SGrant Likely dev_dbg(&spi->dev, "setup: speed %d, sample %s edge, clk %s\n", 914ca632f55SGrant Likely OMAP2_MCSPI_MAX_FREQ >> div, 915ca632f55SGrant Likely (spi->mode & SPI_CPHA) ? "trailing" : "leading", 916ca632f55SGrant Likely (spi->mode & SPI_CPOL) ? "inverted" : "normal"); 917ca632f55SGrant Likely 918ca632f55SGrant Likely return 0; 919ca632f55SGrant Likely } 920ca632f55SGrant Likely 921ddc5cdf1STony Lindgren /* 922ddc5cdf1STony Lindgren * Note that we currently allow DMA only if we get a channel 923ddc5cdf1STony Lindgren * for both rx and tx. Otherwise we'll do PIO for both rx and tx. 924ddc5cdf1STony Lindgren */ 925ca632f55SGrant Likely static int omap2_mcspi_request_dma(struct spi_device *spi) 926ca632f55SGrant Likely { 927ca632f55SGrant Likely struct spi_master *master = spi->master; 928ca632f55SGrant Likely struct omap2_mcspi *mcspi; 929ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 93053741ed8SRussell King dma_cap_mask_t mask; 93153741ed8SRussell King unsigned sig; 932ca632f55SGrant Likely 933ca632f55SGrant Likely mcspi = spi_master_get_devdata(master); 934ca632f55SGrant Likely mcspi_dma = mcspi->dma_channels + spi->chip_select; 935ca632f55SGrant Likely 936ca632f55SGrant Likely init_completion(&mcspi_dma->dma_rx_completion); 937ca632f55SGrant Likely init_completion(&mcspi_dma->dma_tx_completion); 938ca632f55SGrant Likely 93953741ed8SRussell King dma_cap_zero(mask); 94053741ed8SRussell King dma_cap_set(DMA_SLAVE, mask); 94153741ed8SRussell King sig = mcspi_dma->dma_rx_sync_dev; 94274f3aaadSMatt Porter 94374f3aaadSMatt Porter mcspi_dma->dma_rx = 94474f3aaadSMatt Porter dma_request_slave_channel_compat(mask, omap_dma_filter_fn, 94574f3aaadSMatt Porter &sig, &master->dev, 94674f3aaadSMatt Porter mcspi_dma->dma_rx_ch_name); 947ddc5cdf1STony Lindgren if (!mcspi_dma->dma_rx) 948ddc5cdf1STony Lindgren goto no_dma; 949ca632f55SGrant Likely 95053741ed8SRussell King sig = mcspi_dma->dma_tx_sync_dev; 95174f3aaadSMatt Porter mcspi_dma->dma_tx = 95274f3aaadSMatt Porter dma_request_slave_channel_compat(mask, omap_dma_filter_fn, 95374f3aaadSMatt Porter &sig, &master->dev, 95474f3aaadSMatt Porter mcspi_dma->dma_tx_ch_name); 95574f3aaadSMatt Porter 95653741ed8SRussell King if (!mcspi_dma->dma_tx) { 95753741ed8SRussell King dma_release_channel(mcspi_dma->dma_rx); 95853741ed8SRussell King mcspi_dma->dma_rx = NULL; 959ddc5cdf1STony Lindgren goto no_dma; 96053741ed8SRussell King } 961ca632f55SGrant Likely 962ca632f55SGrant Likely return 0; 963ddc5cdf1STony Lindgren 964ddc5cdf1STony Lindgren no_dma: 965ddc5cdf1STony Lindgren dev_warn(&spi->dev, "not using DMA for McSPI\n"); 966ddc5cdf1STony Lindgren return -EAGAIN; 967ca632f55SGrant Likely } 968ca632f55SGrant Likely 969ca632f55SGrant Likely static int omap2_mcspi_setup(struct spi_device *spi) 970ca632f55SGrant Likely { 971ca632f55SGrant Likely int ret; 9721bd897f8SBenoit Cousson struct omap2_mcspi *mcspi = spi_master_get_devdata(spi->master); 9731bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 974ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 975ca632f55SGrant Likely struct omap2_mcspi_cs *cs = spi->controller_state; 976ca632f55SGrant Likely 977ca632f55SGrant Likely mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 978ca632f55SGrant Likely 979ca632f55SGrant Likely if (!cs) { 98010aa5a35SRussell King cs = kzalloc(sizeof *cs, GFP_KERNEL); 981ca632f55SGrant Likely if (!cs) 982ca632f55SGrant Likely return -ENOMEM; 983ca632f55SGrant Likely cs->base = mcspi->base + spi->chip_select * 0x14; 984ca632f55SGrant Likely cs->phys = mcspi->phys + spi->chip_select * 0x14; 985ca632f55SGrant Likely cs->chconf0 = 0; 986ca632f55SGrant Likely spi->controller_state = cs; 987ca632f55SGrant Likely /* Link this to context save list */ 9881bd897f8SBenoit Cousson list_add_tail(&cs->node, &ctx->cs); 989ca632f55SGrant Likely } 990ca632f55SGrant Likely 9918c7494a5SRussell King if (!mcspi_dma->dma_rx || !mcspi_dma->dma_tx) { 992ca632f55SGrant Likely ret = omap2_mcspi_request_dma(spi); 993ddc5cdf1STony Lindgren if (ret < 0 && ret != -EAGAIN) 994ca632f55SGrant Likely return ret; 995ca632f55SGrant Likely } 996ca632f55SGrant Likely 997034d3dc9SShubhrajyoti D ret = pm_runtime_get_sync(mcspi->dev); 998ca632f55SGrant Likely if (ret < 0) 999ca632f55SGrant Likely return ret; 1000ca632f55SGrant Likely 1001ca632f55SGrant Likely ret = omap2_mcspi_setup_transfer(spi, NULL); 1002034d3dc9SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 1003034d3dc9SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 1004ca632f55SGrant Likely 1005ca632f55SGrant Likely return ret; 1006ca632f55SGrant Likely } 1007ca632f55SGrant Likely 1008ca632f55SGrant Likely static void omap2_mcspi_cleanup(struct spi_device *spi) 1009ca632f55SGrant Likely { 1010ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1011ca632f55SGrant Likely struct omap2_mcspi_dma *mcspi_dma; 1012ca632f55SGrant Likely struct omap2_mcspi_cs *cs; 1013ca632f55SGrant Likely 1014ca632f55SGrant Likely mcspi = spi_master_get_devdata(spi->master); 1015ca632f55SGrant Likely 1016ca632f55SGrant Likely if (spi->controller_state) { 1017ca632f55SGrant Likely /* Unlink controller state from context save list */ 1018ca632f55SGrant Likely cs = spi->controller_state; 1019ca632f55SGrant Likely list_del(&cs->node); 1020ca632f55SGrant Likely 102110aa5a35SRussell King kfree(cs); 1022ca632f55SGrant Likely } 1023ca632f55SGrant Likely 1024ca632f55SGrant Likely if (spi->chip_select < spi->master->num_chipselect) { 1025ca632f55SGrant Likely mcspi_dma = &mcspi->dma_channels[spi->chip_select]; 1026ca632f55SGrant Likely 102753741ed8SRussell King if (mcspi_dma->dma_rx) { 102853741ed8SRussell King dma_release_channel(mcspi_dma->dma_rx); 102953741ed8SRussell King mcspi_dma->dma_rx = NULL; 1030ca632f55SGrant Likely } 103153741ed8SRussell King if (mcspi_dma->dma_tx) { 103253741ed8SRussell King dma_release_channel(mcspi_dma->dma_tx); 103353741ed8SRussell King mcspi_dma->dma_tx = NULL; 1034ca632f55SGrant Likely } 1035ca632f55SGrant Likely } 1036ca632f55SGrant Likely } 1037ca632f55SGrant Likely 10385fda88f5SShubhrajyoti D static void omap2_mcspi_work(struct omap2_mcspi *mcspi, struct spi_message *m) 1039ca632f55SGrant Likely { 1040ca632f55SGrant Likely 1041ca632f55SGrant Likely /* We only enable one channel at a time -- the one whose message is 10425fda88f5SShubhrajyoti D * -- although this controller would gladly 1043ca632f55SGrant Likely * arbitrate among multiple channels. This corresponds to "single 1044ca632f55SGrant Likely * channel" master mode. As a side effect, we need to manage the 1045ca632f55SGrant Likely * chipselect with the FORCE bit ... CS != channel enable. 1046ca632f55SGrant Likely */ 10475fda88f5SShubhrajyoti D 1048ca632f55SGrant Likely struct spi_device *spi; 1049ca632f55SGrant Likely struct spi_transfer *t = NULL; 10505cbc7ca9SMatthias Brugger struct spi_master *master; 1051ddc5cdf1STony Lindgren struct omap2_mcspi_dma *mcspi_dma; 1052ca632f55SGrant Likely int cs_active = 0; 1053ca632f55SGrant Likely struct omap2_mcspi_cs *cs; 1054ca632f55SGrant Likely struct omap2_mcspi_device_config *cd; 1055ca632f55SGrant Likely int par_override = 0; 1056ca632f55SGrant Likely int status = 0; 1057ca632f55SGrant Likely u32 chconf; 1058ca632f55SGrant Likely 1059ca632f55SGrant Likely spi = m->spi; 10605cbc7ca9SMatthias Brugger master = spi->master; 1061ddc5cdf1STony Lindgren mcspi_dma = mcspi->dma_channels + spi->chip_select; 1062ca632f55SGrant Likely cs = spi->controller_state; 1063ca632f55SGrant Likely cd = spi->controller_data; 1064ca632f55SGrant Likely 1065d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 0); 1066ca632f55SGrant Likely list_for_each_entry(t, &m->transfers, transfer_list) { 1067ca632f55SGrant Likely if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) { 1068ca632f55SGrant Likely status = -EINVAL; 1069ca632f55SGrant Likely break; 1070ca632f55SGrant Likely } 1071ca632f55SGrant Likely if (par_override || t->speed_hz || t->bits_per_word) { 1072ca632f55SGrant Likely par_override = 1; 1073ca632f55SGrant Likely status = omap2_mcspi_setup_transfer(spi, t); 1074ca632f55SGrant Likely if (status < 0) 1075ca632f55SGrant Likely break; 1076ca632f55SGrant Likely if (!t->speed_hz && !t->bits_per_word) 1077ca632f55SGrant Likely par_override = 0; 1078ca632f55SGrant Likely } 10795cbc7ca9SMatthias Brugger if (cd && cd->cs_per_word) { 10805cbc7ca9SMatthias Brugger chconf = mcspi->ctx.modulctrl; 10815cbc7ca9SMatthias Brugger chconf &= ~OMAP2_MCSPI_MODULCTRL_SINGLE; 10825cbc7ca9SMatthias Brugger mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf); 10835cbc7ca9SMatthias Brugger mcspi->ctx.modulctrl = 10845cbc7ca9SMatthias Brugger mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 10855cbc7ca9SMatthias Brugger } 10865cbc7ca9SMatthias Brugger 1087ca632f55SGrant Likely 1088ca632f55SGrant Likely if (!cs_active) { 1089ca632f55SGrant Likely omap2_mcspi_force_cs(spi, 1); 1090ca632f55SGrant Likely cs_active = 1; 1091ca632f55SGrant Likely } 1092ca632f55SGrant Likely 1093ca632f55SGrant Likely chconf = mcspi_cached_chconf0(spi); 1094ca632f55SGrant Likely chconf &= ~OMAP2_MCSPI_CHCONF_TRM_MASK; 1095ca632f55SGrant Likely chconf &= ~OMAP2_MCSPI_CHCONF_TURBO; 1096ca632f55SGrant Likely 1097ca632f55SGrant Likely if (t->tx_buf == NULL) 1098ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TRM_RX_ONLY; 1099ca632f55SGrant Likely else if (t->rx_buf == NULL) 1100ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY; 1101ca632f55SGrant Likely 1102ca632f55SGrant Likely if (cd && cd->turbo_mode && t->tx_buf == NULL) { 1103ca632f55SGrant Likely /* Turbo mode is for more than one word */ 1104ca632f55SGrant Likely if (t->len > ((cs->word_len + 7) >> 3)) 1105ca632f55SGrant Likely chconf |= OMAP2_MCSPI_CHCONF_TURBO; 1106ca632f55SGrant Likely } 1107ca632f55SGrant Likely 1108ca632f55SGrant Likely mcspi_write_chconf0(spi, chconf); 1109ca632f55SGrant Likely 1110ca632f55SGrant Likely if (t->len) { 1111ca632f55SGrant Likely unsigned count; 1112ca632f55SGrant Likely 1113d33f473dSIllia Smyrnov if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && 1114d33f473dSIllia Smyrnov (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)) 1115d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 1); 1116d33f473dSIllia Smyrnov 1117d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 1); 1118d33f473dSIllia Smyrnov 1119ca632f55SGrant Likely /* RX_ONLY mode needs dummy data in TX reg */ 1120ca632f55SGrant Likely if (t->tx_buf == NULL) 1121ca632f55SGrant Likely __raw_writel(0, cs->base 1122ca632f55SGrant Likely + OMAP2_MCSPI_TX0); 1123ca632f55SGrant Likely 1124ddc5cdf1STony Lindgren if ((mcspi_dma->dma_rx && mcspi_dma->dma_tx) && 1125ddc5cdf1STony Lindgren (m->is_dma_mapped || t->len >= DMA_MIN_BYTES)) 1126ca632f55SGrant Likely count = omap2_mcspi_txrx_dma(spi, t); 1127ca632f55SGrant Likely else 1128ca632f55SGrant Likely count = omap2_mcspi_txrx_pio(spi, t); 1129ca632f55SGrant Likely m->actual_length += count; 1130ca632f55SGrant Likely 1131ca632f55SGrant Likely if (count != t->len) { 1132ca632f55SGrant Likely status = -EIO; 1133ca632f55SGrant Likely break; 1134ca632f55SGrant Likely } 1135ca632f55SGrant Likely } 1136ca632f55SGrant Likely 1137ca632f55SGrant Likely if (t->delay_usecs) 1138ca632f55SGrant Likely udelay(t->delay_usecs); 1139ca632f55SGrant Likely 1140ca632f55SGrant Likely /* ignore the "leave it on after last xfer" hint */ 1141ca632f55SGrant Likely if (t->cs_change) { 1142ca632f55SGrant Likely omap2_mcspi_force_cs(spi, 0); 1143ca632f55SGrant Likely cs_active = 0; 1144ca632f55SGrant Likely } 1145d33f473dSIllia Smyrnov 1146d33f473dSIllia Smyrnov omap2_mcspi_set_enable(spi, 0); 1147d33f473dSIllia Smyrnov 1148d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0) 1149d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 0); 1150ca632f55SGrant Likely } 1151ca632f55SGrant Likely /* Restore defaults if they were overriden */ 1152ca632f55SGrant Likely if (par_override) { 1153ca632f55SGrant Likely par_override = 0; 1154ca632f55SGrant Likely status = omap2_mcspi_setup_transfer(spi, NULL); 1155ca632f55SGrant Likely } 1156ca632f55SGrant Likely 1157ca632f55SGrant Likely if (cs_active) 1158ca632f55SGrant Likely omap2_mcspi_force_cs(spi, 0); 1159ca632f55SGrant Likely 11605cbc7ca9SMatthias Brugger if (cd && cd->cs_per_word) { 11615cbc7ca9SMatthias Brugger chconf = mcspi->ctx.modulctrl; 11625cbc7ca9SMatthias Brugger chconf |= OMAP2_MCSPI_MODULCTRL_SINGLE; 11635cbc7ca9SMatthias Brugger mcspi_write_reg(master, OMAP2_MCSPI_MODULCTRL, chconf); 11645cbc7ca9SMatthias Brugger mcspi->ctx.modulctrl = 11655cbc7ca9SMatthias Brugger mcspi_read_cs_reg(spi, OMAP2_MCSPI_MODULCTRL); 11665cbc7ca9SMatthias Brugger } 11675cbc7ca9SMatthias Brugger 1168ca632f55SGrant Likely omap2_mcspi_set_enable(spi, 0); 1169ca632f55SGrant Likely 1170d33f473dSIllia Smyrnov if (mcspi->fifo_depth > 0 && t) 1171d33f473dSIllia Smyrnov omap2_mcspi_set_fifo(spi, t, 0); 1172ca632f55SGrant Likely 1173d33f473dSIllia Smyrnov m->status = status; 1174ca632f55SGrant Likely } 1175ca632f55SGrant Likely 11765fda88f5SShubhrajyoti D static int omap2_mcspi_transfer_one_message(struct spi_master *master, 11775fda88f5SShubhrajyoti D struct spi_message *m) 1178ca632f55SGrant Likely { 1179ddc5cdf1STony Lindgren struct spi_device *spi; 1180ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1181ddc5cdf1STony Lindgren struct omap2_mcspi_dma *mcspi_dma; 1182ca632f55SGrant Likely struct spi_transfer *t; 1183ca632f55SGrant Likely 1184ddc5cdf1STony Lindgren spi = m->spi; 11855fda88f5SShubhrajyoti D mcspi = spi_master_get_devdata(master); 1186ddc5cdf1STony Lindgren mcspi_dma = mcspi->dma_channels + spi->chip_select; 1187ca632f55SGrant Likely m->actual_length = 0; 1188ca632f55SGrant Likely m->status = 0; 1189ca632f55SGrant Likely 1190ca632f55SGrant Likely /* reject invalid messages and transfers */ 11915fda88f5SShubhrajyoti D if (list_empty(&m->transfers)) 1192ca632f55SGrant Likely return -EINVAL; 1193ca632f55SGrant Likely list_for_each_entry(t, &m->transfers, transfer_list) { 1194ca632f55SGrant Likely const void *tx_buf = t->tx_buf; 1195ca632f55SGrant Likely void *rx_buf = t->rx_buf; 1196ca632f55SGrant Likely unsigned len = t->len; 1197ca632f55SGrant Likely 1198ca632f55SGrant Likely if (t->speed_hz > OMAP2_MCSPI_MAX_FREQ 119924778be2SStephen Warren || (len && !(rx_buf || tx_buf))) { 12005fda88f5SShubhrajyoti D dev_dbg(mcspi->dev, "transfer: %d Hz, %d %s%s, %d bpw\n", 1201ca632f55SGrant Likely t->speed_hz, 1202ca632f55SGrant Likely len, 1203ca632f55SGrant Likely tx_buf ? "tx" : "", 1204ca632f55SGrant Likely rx_buf ? "rx" : "", 1205ca632f55SGrant Likely t->bits_per_word); 1206ca632f55SGrant Likely return -EINVAL; 1207ca632f55SGrant Likely } 1208ca632f55SGrant Likely if (t->speed_hz && t->speed_hz < (OMAP2_MCSPI_MAX_FREQ >> 15)) { 12095fda88f5SShubhrajyoti D dev_dbg(mcspi->dev, "speed_hz %d below minimum %d Hz\n", 1210ca632f55SGrant Likely t->speed_hz, 1211ca632f55SGrant Likely OMAP2_MCSPI_MAX_FREQ >> 15); 1212ca632f55SGrant Likely return -EINVAL; 1213ca632f55SGrant Likely } 1214ca632f55SGrant Likely 1215ca632f55SGrant Likely if (m->is_dma_mapped || len < DMA_MIN_BYTES) 1216ca632f55SGrant Likely continue; 1217ca632f55SGrant Likely 1218ddc5cdf1STony Lindgren if (mcspi_dma->dma_tx && tx_buf != NULL) { 12195fda88f5SShubhrajyoti D t->tx_dma = dma_map_single(mcspi->dev, (void *) tx_buf, 1220ca632f55SGrant Likely len, DMA_TO_DEVICE); 12215fda88f5SShubhrajyoti D if (dma_mapping_error(mcspi->dev, t->tx_dma)) { 12225fda88f5SShubhrajyoti D dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", 1223ca632f55SGrant Likely 'T', len); 1224ca632f55SGrant Likely return -EINVAL; 1225ca632f55SGrant Likely } 1226ca632f55SGrant Likely } 1227ddc5cdf1STony Lindgren if (mcspi_dma->dma_rx && rx_buf != NULL) { 12285fda88f5SShubhrajyoti D t->rx_dma = dma_map_single(mcspi->dev, rx_buf, t->len, 1229ca632f55SGrant Likely DMA_FROM_DEVICE); 12305fda88f5SShubhrajyoti D if (dma_mapping_error(mcspi->dev, t->rx_dma)) { 12315fda88f5SShubhrajyoti D dev_dbg(mcspi->dev, "dma %cX %d bytes error\n", 1232ca632f55SGrant Likely 'R', len); 1233ca632f55SGrant Likely if (tx_buf != NULL) 12345fda88f5SShubhrajyoti D dma_unmap_single(mcspi->dev, t->tx_dma, 1235ca632f55SGrant Likely len, DMA_TO_DEVICE); 1236ca632f55SGrant Likely return -EINVAL; 1237ca632f55SGrant Likely } 1238ca632f55SGrant Likely } 1239ca632f55SGrant Likely } 1240ca632f55SGrant Likely 12415fda88f5SShubhrajyoti D omap2_mcspi_work(mcspi, m); 12425fda88f5SShubhrajyoti D spi_finalize_current_message(master); 1243ca632f55SGrant Likely return 0; 1244ca632f55SGrant Likely } 1245ca632f55SGrant Likely 1246fd4a319bSGrant Likely static int omap2_mcspi_master_setup(struct omap2_mcspi *mcspi) 1247ca632f55SGrant Likely { 1248ca632f55SGrant Likely struct spi_master *master = mcspi->master; 12491bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1250ca632f55SGrant Likely int ret = 0; 1251ca632f55SGrant Likely 1252034d3dc9SShubhrajyoti D ret = pm_runtime_get_sync(mcspi->dev); 1253ca632f55SGrant Likely if (ret < 0) 1254ca632f55SGrant Likely return ret; 1255ca632f55SGrant Likely 125639f8052dSShubhrajyoti D mcspi_write_reg(master, OMAP2_MCSPI_WAKEUPENABLE, 125739f8052dSShubhrajyoti D OMAP2_MCSPI_WAKEUPENABLE_WKEN); 125839f8052dSShubhrajyoti D ctx->wakeupenable = OMAP2_MCSPI_WAKEUPENABLE_WKEN; 1259ca632f55SGrant Likely 1260ca632f55SGrant Likely omap2_mcspi_set_master_mode(master); 1261034d3dc9SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 1262034d3dc9SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 1263ca632f55SGrant Likely return 0; 1264ca632f55SGrant Likely } 1265ca632f55SGrant Likely 1266ca632f55SGrant Likely static int omap_mcspi_runtime_resume(struct device *dev) 1267ca632f55SGrant Likely { 1268ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1269ca632f55SGrant Likely struct spi_master *master; 1270ca632f55SGrant Likely 1271ca632f55SGrant Likely master = dev_get_drvdata(dev); 1272ca632f55SGrant Likely mcspi = spi_master_get_devdata(master); 1273ca632f55SGrant Likely omap2_mcspi_restore_ctx(mcspi); 1274ca632f55SGrant Likely 1275ca632f55SGrant Likely return 0; 1276ca632f55SGrant Likely } 1277ca632f55SGrant Likely 1278d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap2_pdata = { 1279d5a80031SBenoit Cousson .regs_offset = 0, 1280d5a80031SBenoit Cousson }; 1281d5a80031SBenoit Cousson 1282d5a80031SBenoit Cousson static struct omap2_mcspi_platform_config omap4_pdata = { 1283d5a80031SBenoit Cousson .regs_offset = OMAP4_MCSPI_REG_OFFSET, 1284d5a80031SBenoit Cousson }; 1285d5a80031SBenoit Cousson 1286d5a80031SBenoit Cousson static const struct of_device_id omap_mcspi_of_match[] = { 1287d5a80031SBenoit Cousson { 1288d5a80031SBenoit Cousson .compatible = "ti,omap2-mcspi", 1289d5a80031SBenoit Cousson .data = &omap2_pdata, 1290d5a80031SBenoit Cousson }, 1291d5a80031SBenoit Cousson { 1292d5a80031SBenoit Cousson .compatible = "ti,omap4-mcspi", 1293d5a80031SBenoit Cousson .data = &omap4_pdata, 1294d5a80031SBenoit Cousson }, 1295d5a80031SBenoit Cousson { }, 1296d5a80031SBenoit Cousson }; 1297d5a80031SBenoit Cousson MODULE_DEVICE_TABLE(of, omap_mcspi_of_match); 1298ca632f55SGrant Likely 1299fd4a319bSGrant Likely static int omap2_mcspi_probe(struct platform_device *pdev) 1300ca632f55SGrant Likely { 1301ca632f55SGrant Likely struct spi_master *master; 130283a01e72SUwe Kleine-König const struct omap2_mcspi_platform_config *pdata; 1303ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1304ca632f55SGrant Likely struct resource *r; 1305ca632f55SGrant Likely int status = 0, i; 1306d5a80031SBenoit Cousson u32 regs_offset = 0; 1307d5a80031SBenoit Cousson static int bus_num = 1; 1308d5a80031SBenoit Cousson struct device_node *node = pdev->dev.of_node; 1309d5a80031SBenoit Cousson const struct of_device_id *match; 1310ca632f55SGrant Likely 1311ca632f55SGrant Likely master = spi_alloc_master(&pdev->dev, sizeof *mcspi); 1312ca632f55SGrant Likely if (master == NULL) { 1313ca632f55SGrant Likely dev_dbg(&pdev->dev, "master allocation failed\n"); 1314ca632f55SGrant Likely return -ENOMEM; 1315ca632f55SGrant Likely } 1316ca632f55SGrant Likely 1317ca632f55SGrant Likely /* the spi->mode bits understood by this driver: */ 1318ca632f55SGrant Likely master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; 131924778be2SStephen Warren master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 1320ca632f55SGrant Likely master->setup = omap2_mcspi_setup; 13215fda88f5SShubhrajyoti D master->prepare_transfer_hardware = omap2_prepare_transfer; 13225fda88f5SShubhrajyoti D master->unprepare_transfer_hardware = omap2_unprepare_transfer; 13235fda88f5SShubhrajyoti D master->transfer_one_message = omap2_mcspi_transfer_one_message; 1324ca632f55SGrant Likely master->cleanup = omap2_mcspi_cleanup; 1325d5a80031SBenoit Cousson master->dev.of_node = node; 1326d5a80031SBenoit Cousson 132724b5a82cSJingoo Han platform_set_drvdata(pdev, master); 13280384e90bSDaniel Mack 13290384e90bSDaniel Mack mcspi = spi_master_get_devdata(master); 13300384e90bSDaniel Mack mcspi->master = master; 13310384e90bSDaniel Mack 1332d5a80031SBenoit Cousson match = of_match_device(omap_mcspi_of_match, &pdev->dev); 1333d5a80031SBenoit Cousson if (match) { 1334d5a80031SBenoit Cousson u32 num_cs = 1; /* default number of chipselect */ 1335d5a80031SBenoit Cousson pdata = match->data; 1336d5a80031SBenoit Cousson 1337d5a80031SBenoit Cousson of_property_read_u32(node, "ti,spi-num-cs", &num_cs); 1338d5a80031SBenoit Cousson master->num_chipselect = num_cs; 1339d5a80031SBenoit Cousson master->bus_num = bus_num++; 13402cd45179SDaniel Mack if (of_get_property(node, "ti,pindir-d0-out-d1-in", NULL)) 13412cd45179SDaniel Mack mcspi->pin_dir = MCSPI_PINDIR_D0_OUT_D1_IN; 1342d5a80031SBenoit Cousson } else { 1343*8074cf06SJingoo Han pdata = dev_get_platdata(&pdev->dev); 1344ca632f55SGrant Likely master->num_chipselect = pdata->num_cs; 1345d5a80031SBenoit Cousson if (pdev->id != -1) 1346d5a80031SBenoit Cousson master->bus_num = pdev->id; 13470384e90bSDaniel Mack mcspi->pin_dir = pdata->pin_dir; 1348d5a80031SBenoit Cousson } 1349d5a80031SBenoit Cousson regs_offset = pdata->regs_offset; 1350ca632f55SGrant Likely 1351ca632f55SGrant Likely r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1352ca632f55SGrant Likely if (r == NULL) { 1353ca632f55SGrant Likely status = -ENODEV; 135439f1b565SShubhrajyoti D goto free_master; 1355ca632f55SGrant Likely } 13561458d160SShubhrajyoti D 1357d5a80031SBenoit Cousson r->start += regs_offset; 1358d5a80031SBenoit Cousson r->end += regs_offset; 13591458d160SShubhrajyoti D mcspi->phys = r->start; 1360ca632f55SGrant Likely 1361b0ee5605SThierry Reding mcspi->base = devm_ioremap_resource(&pdev->dev, r); 1362b0ee5605SThierry Reding if (IS_ERR(mcspi->base)) { 1363b0ee5605SThierry Reding status = PTR_ERR(mcspi->base); 13641a77b127SShubhrajyoti D goto free_master; 1365ca632f55SGrant Likely } 1366ca632f55SGrant Likely 1367ca632f55SGrant Likely mcspi->dev = &pdev->dev; 1368ca632f55SGrant Likely 13691bd897f8SBenoit Cousson INIT_LIST_HEAD(&mcspi->ctx.cs); 1370ca632f55SGrant Likely 1371ca632f55SGrant Likely mcspi->dma_channels = kcalloc(master->num_chipselect, 1372ca632f55SGrant Likely sizeof(struct omap2_mcspi_dma), 1373ca632f55SGrant Likely GFP_KERNEL); 1374ca632f55SGrant Likely 1375ca632f55SGrant Likely if (mcspi->dma_channels == NULL) 13761a77b127SShubhrajyoti D goto free_master; 1377ca632f55SGrant Likely 1378ca632f55SGrant Likely for (i = 0; i < master->num_chipselect; i++) { 137974f3aaadSMatt Porter char *dma_rx_ch_name = mcspi->dma_channels[i].dma_rx_ch_name; 138074f3aaadSMatt Porter char *dma_tx_ch_name = mcspi->dma_channels[i].dma_tx_ch_name; 1381ca632f55SGrant Likely struct resource *dma_res; 1382ca632f55SGrant Likely 138374f3aaadSMatt Porter sprintf(dma_rx_ch_name, "rx%d", i); 138474f3aaadSMatt Porter if (!pdev->dev.of_node) { 138574f3aaadSMatt Porter dma_res = 138674f3aaadSMatt Porter platform_get_resource_byname(pdev, 138774f3aaadSMatt Porter IORESOURCE_DMA, 138874f3aaadSMatt Porter dma_rx_ch_name); 1389ca632f55SGrant Likely if (!dma_res) { 139074f3aaadSMatt Porter dev_dbg(&pdev->dev, 139174f3aaadSMatt Porter "cannot get DMA RX channel\n"); 1392ca632f55SGrant Likely status = -ENODEV; 1393ca632f55SGrant Likely break; 1394ca632f55SGrant Likely } 1395ca632f55SGrant Likely 139674f3aaadSMatt Porter mcspi->dma_channels[i].dma_rx_sync_dev = 139774f3aaadSMatt Porter dma_res->start; 139874f3aaadSMatt Porter } 139974f3aaadSMatt Porter sprintf(dma_tx_ch_name, "tx%d", i); 140074f3aaadSMatt Porter if (!pdev->dev.of_node) { 140174f3aaadSMatt Porter dma_res = 140274f3aaadSMatt Porter platform_get_resource_byname(pdev, 140374f3aaadSMatt Porter IORESOURCE_DMA, 140474f3aaadSMatt Porter dma_tx_ch_name); 1405ca632f55SGrant Likely if (!dma_res) { 140674f3aaadSMatt Porter dev_dbg(&pdev->dev, 140774f3aaadSMatt Porter "cannot get DMA TX channel\n"); 1408ca632f55SGrant Likely status = -ENODEV; 1409ca632f55SGrant Likely break; 1410ca632f55SGrant Likely } 1411ca632f55SGrant Likely 141274f3aaadSMatt Porter mcspi->dma_channels[i].dma_tx_sync_dev = 141374f3aaadSMatt Porter dma_res->start; 141474f3aaadSMatt Porter } 1415ca632f55SGrant Likely } 1416ca632f55SGrant Likely 141739f1b565SShubhrajyoti D if (status < 0) 141839f1b565SShubhrajyoti D goto dma_chnl_free; 141939f1b565SShubhrajyoti D 142027b5284cSShubhrajyoti D pm_runtime_use_autosuspend(&pdev->dev); 142127b5284cSShubhrajyoti D pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT); 1422ca632f55SGrant Likely pm_runtime_enable(&pdev->dev); 1423ca632f55SGrant Likely 1424142e07beSWei Yongjun status = omap2_mcspi_master_setup(mcspi); 1425142e07beSWei Yongjun if (status < 0) 142639f1b565SShubhrajyoti D goto disable_pm; 1427ca632f55SGrant Likely 1428ca632f55SGrant Likely status = spi_register_master(master); 1429ca632f55SGrant Likely if (status < 0) 143037a2d84aSShubhrajyoti D goto disable_pm; 1431ca632f55SGrant Likely 1432ca632f55SGrant Likely return status; 1433ca632f55SGrant Likely 143439f1b565SShubhrajyoti D disable_pm: 1435751c925cSShubhrajyoti D pm_runtime_disable(&pdev->dev); 143639f1b565SShubhrajyoti D dma_chnl_free: 1437ca632f55SGrant Likely kfree(mcspi->dma_channels); 143839f1b565SShubhrajyoti D free_master: 143937a2d84aSShubhrajyoti D spi_master_put(master); 1440ca632f55SGrant Likely return status; 1441ca632f55SGrant Likely } 1442ca632f55SGrant Likely 1443fd4a319bSGrant Likely static int omap2_mcspi_remove(struct platform_device *pdev) 1444ca632f55SGrant Likely { 1445ca632f55SGrant Likely struct spi_master *master; 1446ca632f55SGrant Likely struct omap2_mcspi *mcspi; 1447ca632f55SGrant Likely struct omap2_mcspi_dma *dma_channels; 1448ca632f55SGrant Likely 144924b5a82cSJingoo Han master = platform_get_drvdata(pdev); 1450ca632f55SGrant Likely mcspi = spi_master_get_devdata(master); 1451ca632f55SGrant Likely dma_channels = mcspi->dma_channels; 1452ca632f55SGrant Likely 1453a93a2029SShubhrajyoti D pm_runtime_put_sync(mcspi->dev); 1454751c925cSShubhrajyoti D pm_runtime_disable(&pdev->dev); 1455ca632f55SGrant Likely 1456ca632f55SGrant Likely spi_unregister_master(master); 1457ca632f55SGrant Likely kfree(dma_channels); 1458ca632f55SGrant Likely 1459ca632f55SGrant Likely return 0; 1460ca632f55SGrant Likely } 1461ca632f55SGrant Likely 1462ca632f55SGrant Likely /* work with hotplug and coldplug */ 1463ca632f55SGrant Likely MODULE_ALIAS("platform:omap2_mcspi"); 1464ca632f55SGrant Likely 1465ca632f55SGrant Likely #ifdef CONFIG_SUSPEND 1466ca632f55SGrant Likely /* 1467ca632f55SGrant Likely * When SPI wake up from off-mode, CS is in activate state. If it was in 1468ca632f55SGrant Likely * unactive state when driver was suspend, then force it to unactive state at 1469ca632f55SGrant Likely * wake up. 1470ca632f55SGrant Likely */ 1471ca632f55SGrant Likely static int omap2_mcspi_resume(struct device *dev) 1472ca632f55SGrant Likely { 1473ca632f55SGrant Likely struct spi_master *master = dev_get_drvdata(dev); 1474ca632f55SGrant Likely struct omap2_mcspi *mcspi = spi_master_get_devdata(master); 14751bd897f8SBenoit Cousson struct omap2_mcspi_regs *ctx = &mcspi->ctx; 1476ca632f55SGrant Likely struct omap2_mcspi_cs *cs; 1477ca632f55SGrant Likely 1478034d3dc9SShubhrajyoti D pm_runtime_get_sync(mcspi->dev); 14791bd897f8SBenoit Cousson list_for_each_entry(cs, &ctx->cs, node) { 1480ca632f55SGrant Likely if ((cs->chconf0 & OMAP2_MCSPI_CHCONF_FORCE) == 0) { 1481ca632f55SGrant Likely /* 1482ca632f55SGrant Likely * We need to toggle CS state for OMAP take this 1483ca632f55SGrant Likely * change in account. 1484ca632f55SGrant Likely */ 1485af4e944dSShubhrajyoti D cs->chconf0 |= OMAP2_MCSPI_CHCONF_FORCE; 1486ca632f55SGrant Likely __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); 1487af4e944dSShubhrajyoti D cs->chconf0 &= ~OMAP2_MCSPI_CHCONF_FORCE; 1488ca632f55SGrant Likely __raw_writel(cs->chconf0, cs->base + OMAP2_MCSPI_CHCONF0); 1489ca632f55SGrant Likely } 1490ca632f55SGrant Likely } 1491034d3dc9SShubhrajyoti D pm_runtime_mark_last_busy(mcspi->dev); 1492034d3dc9SShubhrajyoti D pm_runtime_put_autosuspend(mcspi->dev); 1493ca632f55SGrant Likely return 0; 1494ca632f55SGrant Likely } 1495ca632f55SGrant Likely #else 1496ca632f55SGrant Likely #define omap2_mcspi_resume NULL 1497ca632f55SGrant Likely #endif 1498ca632f55SGrant Likely 1499ca632f55SGrant Likely static const struct dev_pm_ops omap2_mcspi_pm_ops = { 1500ca632f55SGrant Likely .resume = omap2_mcspi_resume, 1501ca632f55SGrant Likely .runtime_resume = omap_mcspi_runtime_resume, 1502ca632f55SGrant Likely }; 1503ca632f55SGrant Likely 1504ca632f55SGrant Likely static struct platform_driver omap2_mcspi_driver = { 1505ca632f55SGrant Likely .driver = { 1506ca632f55SGrant Likely .name = "omap2_mcspi", 1507ca632f55SGrant Likely .owner = THIS_MODULE, 1508d5a80031SBenoit Cousson .pm = &omap2_mcspi_pm_ops, 1509d5a80031SBenoit Cousson .of_match_table = omap_mcspi_of_match, 1510ca632f55SGrant Likely }, 15117d6b6d83SFelipe Balbi .probe = omap2_mcspi_probe, 1512fd4a319bSGrant Likely .remove = omap2_mcspi_remove, 1513ca632f55SGrant Likely }; 1514ca632f55SGrant Likely 15159fdca9dfSFelipe Balbi module_platform_driver(omap2_mcspi_driver); 1516ca632f55SGrant Likely MODULE_LICENSE("GPL"); 1517