1505a1495SSourav Poddar /* 2505a1495SSourav Poddar * TI QSPI driver 3505a1495SSourav Poddar * 4505a1495SSourav Poddar * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com 5505a1495SSourav Poddar * Author: Sourav Poddar <sourav.poddar@ti.com> 6505a1495SSourav Poddar * 7505a1495SSourav Poddar * This program is free software; you can redistribute it and/or 8505a1495SSourav Poddar * modify it under the terms of the GPLv2. 9505a1495SSourav Poddar * 10505a1495SSourav Poddar * This program is distributed in the hope that it will be useful, 11505a1495SSourav Poddar * but WITHOUT ANY WARRANTY; without even the implied warranty of 12505a1495SSourav Poddar * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the 13505a1495SSourav Poddar * GNU General Public License for more details. 14505a1495SSourav Poddar */ 15505a1495SSourav Poddar 16505a1495SSourav Poddar #include <linux/kernel.h> 17505a1495SSourav Poddar #include <linux/init.h> 18505a1495SSourav Poddar #include <linux/interrupt.h> 19505a1495SSourav Poddar #include <linux/module.h> 20505a1495SSourav Poddar #include <linux/device.h> 21505a1495SSourav Poddar #include <linux/delay.h> 22505a1495SSourav Poddar #include <linux/dma-mapping.h> 23505a1495SSourav Poddar #include <linux/dmaengine.h> 24505a1495SSourav Poddar #include <linux/omap-dma.h> 25505a1495SSourav Poddar #include <linux/platform_device.h> 26505a1495SSourav Poddar #include <linux/err.h> 27505a1495SSourav Poddar #include <linux/clk.h> 28505a1495SSourav Poddar #include <linux/io.h> 29505a1495SSourav Poddar #include <linux/slab.h> 30505a1495SSourav Poddar #include <linux/pm_runtime.h> 31505a1495SSourav Poddar #include <linux/of.h> 32505a1495SSourav Poddar #include <linux/of_device.h> 33505a1495SSourav Poddar #include <linux/pinctrl/consumer.h> 34505a1495SSourav Poddar 35505a1495SSourav Poddar #include <linux/spi/spi.h> 36505a1495SSourav Poddar 37505a1495SSourav Poddar struct ti_qspi_regs { 38505a1495SSourav Poddar u32 clkctrl; 39505a1495SSourav Poddar }; 40505a1495SSourav Poddar 41505a1495SSourav Poddar struct ti_qspi { 42505a1495SSourav Poddar /* list synchronization */ 43505a1495SSourav Poddar struct mutex list_lock; 44505a1495SSourav Poddar 45505a1495SSourav Poddar struct spi_master *master; 46505a1495SSourav Poddar void __iomem *base; 476b3938aeSSourav Poddar void __iomem *ctrl_base; 486b3938aeSSourav Poddar void __iomem *mmap_base; 49505a1495SSourav Poddar struct clk *fclk; 50505a1495SSourav Poddar struct device *dev; 51505a1495SSourav Poddar 52505a1495SSourav Poddar struct ti_qspi_regs ctx_reg; 53505a1495SSourav Poddar 54505a1495SSourav Poddar u32 spi_max_frequency; 55505a1495SSourav Poddar u32 cmd; 56505a1495SSourav Poddar u32 dc; 576b3938aeSSourav Poddar 586b3938aeSSourav Poddar bool ctrl_mod; 59505a1495SSourav Poddar }; 60505a1495SSourav Poddar 61505a1495SSourav Poddar #define QSPI_PID (0x0) 62505a1495SSourav Poddar #define QSPI_SYSCONFIG (0x10) 63505a1495SSourav Poddar #define QSPI_SPI_CLOCK_CNTRL_REG (0x40) 64505a1495SSourav Poddar #define QSPI_SPI_DC_REG (0x44) 65505a1495SSourav Poddar #define QSPI_SPI_CMD_REG (0x48) 66505a1495SSourav Poddar #define QSPI_SPI_STATUS_REG (0x4c) 67505a1495SSourav Poddar #define QSPI_SPI_DATA_REG (0x50) 68505a1495SSourav Poddar #define QSPI_SPI_SETUP0_REG (0x54) 69505a1495SSourav Poddar #define QSPI_SPI_SWITCH_REG (0x64) 70505a1495SSourav Poddar #define QSPI_SPI_SETUP1_REG (0x58) 71505a1495SSourav Poddar #define QSPI_SPI_SETUP2_REG (0x5c) 72505a1495SSourav Poddar #define QSPI_SPI_SETUP3_REG (0x60) 73505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_1 (0x68) 74505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_2 (0x6c) 75505a1495SSourav Poddar #define QSPI_SPI_DATA_REG_3 (0x70) 76505a1495SSourav Poddar 77505a1495SSourav Poddar #define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000) 78505a1495SSourav Poddar 79505a1495SSourav Poddar #define QSPI_FCLK 192000000 80505a1495SSourav Poddar 81505a1495SSourav Poddar /* Clock Control */ 82505a1495SSourav Poddar #define QSPI_CLK_EN (1 << 31) 83505a1495SSourav Poddar #define QSPI_CLK_DIV_MAX 0xffff 84505a1495SSourav Poddar 85505a1495SSourav Poddar /* Command */ 86505a1495SSourav Poddar #define QSPI_EN_CS(n) (n << 28) 87505a1495SSourav Poddar #define QSPI_WLEN(n) ((n - 1) << 19) 88505a1495SSourav Poddar #define QSPI_3_PIN (1 << 18) 89505a1495SSourav Poddar #define QSPI_RD_SNGL (1 << 16) 90505a1495SSourav Poddar #define QSPI_WR_SNGL (2 << 16) 91505a1495SSourav Poddar #define QSPI_RD_DUAL (3 << 16) 92505a1495SSourav Poddar #define QSPI_RD_QUAD (7 << 16) 93505a1495SSourav Poddar #define QSPI_INVAL (4 << 16) 94505a1495SSourav Poddar #define QSPI_FLEN(n) ((n - 1) << 0) 95f682c4ffSVignesh R #define QSPI_WLEN_MAX_BITS 128 96f682c4ffSVignesh R #define QSPI_WLEN_MAX_BYTES 16 97505a1495SSourav Poddar 98505a1495SSourav Poddar /* STATUS REGISTER */ 9900611047SMugunthan V N #define BUSY 0x01 100505a1495SSourav Poddar #define WC 0x02 101505a1495SSourav Poddar 102505a1495SSourav Poddar /* Device Control */ 103505a1495SSourav Poddar #define QSPI_DD(m, n) (m << (3 + n * 8)) 104505a1495SSourav Poddar #define QSPI_CKPHA(n) (1 << (2 + n * 8)) 105505a1495SSourav Poddar #define QSPI_CSPOL(n) (1 << (1 + n * 8)) 106505a1495SSourav Poddar #define QSPI_CKPOL(n) (1 << (n * 8)) 107505a1495SSourav Poddar 108505a1495SSourav Poddar #define QSPI_FRAME 4096 109505a1495SSourav Poddar 110505a1495SSourav Poddar #define QSPI_AUTOSUSPEND_TIMEOUT 2000 111505a1495SSourav Poddar 112505a1495SSourav Poddar static inline unsigned long ti_qspi_read(struct ti_qspi *qspi, 113505a1495SSourav Poddar unsigned long reg) 114505a1495SSourav Poddar { 115505a1495SSourav Poddar return readl(qspi->base + reg); 116505a1495SSourav Poddar } 117505a1495SSourav Poddar 118505a1495SSourav Poddar static inline void ti_qspi_write(struct ti_qspi *qspi, 119505a1495SSourav Poddar unsigned long val, unsigned long reg) 120505a1495SSourav Poddar { 121505a1495SSourav Poddar writel(val, qspi->base + reg); 122505a1495SSourav Poddar } 123505a1495SSourav Poddar 124505a1495SSourav Poddar static int ti_qspi_setup(struct spi_device *spi) 125505a1495SSourav Poddar { 126505a1495SSourav Poddar struct ti_qspi *qspi = spi_master_get_devdata(spi->master); 127505a1495SSourav Poddar struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; 128505a1495SSourav Poddar int clk_div = 0, ret; 129505a1495SSourav Poddar u32 clk_ctrl_reg, clk_rate, clk_mask; 130505a1495SSourav Poddar 131505a1495SSourav Poddar if (spi->master->busy) { 132505a1495SSourav Poddar dev_dbg(qspi->dev, "master busy doing other trasnfers\n"); 133505a1495SSourav Poddar return -EBUSY; 134505a1495SSourav Poddar } 135505a1495SSourav Poddar 136505a1495SSourav Poddar if (!qspi->spi_max_frequency) { 137505a1495SSourav Poddar dev_err(qspi->dev, "spi max frequency not defined\n"); 138505a1495SSourav Poddar return -EINVAL; 139505a1495SSourav Poddar } 140505a1495SSourav Poddar 141505a1495SSourav Poddar clk_rate = clk_get_rate(qspi->fclk); 142505a1495SSourav Poddar 143505a1495SSourav Poddar clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1; 144505a1495SSourav Poddar 145505a1495SSourav Poddar if (clk_div < 0) { 146505a1495SSourav Poddar dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n"); 147505a1495SSourav Poddar return -EINVAL; 148505a1495SSourav Poddar } 149505a1495SSourav Poddar 150505a1495SSourav Poddar if (clk_div > QSPI_CLK_DIV_MAX) { 151505a1495SSourav Poddar dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n", 152505a1495SSourav Poddar QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1); 153505a1495SSourav Poddar return -EINVAL; 154505a1495SSourav Poddar } 155505a1495SSourav Poddar 156505a1495SSourav Poddar dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", 157505a1495SSourav Poddar qspi->spi_max_frequency, clk_div); 158505a1495SSourav Poddar 159505a1495SSourav Poddar ret = pm_runtime_get_sync(qspi->dev); 16005b96675SSourav Poddar if (ret < 0) { 161505a1495SSourav Poddar dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); 162505a1495SSourav Poddar return ret; 163505a1495SSourav Poddar } 164505a1495SSourav Poddar 165505a1495SSourav Poddar clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG); 166505a1495SSourav Poddar 167505a1495SSourav Poddar clk_ctrl_reg &= ~QSPI_CLK_EN; 168505a1495SSourav Poddar 169505a1495SSourav Poddar /* disable SCLK */ 170505a1495SSourav Poddar ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG); 171505a1495SSourav Poddar 172505a1495SSourav Poddar /* enable SCLK */ 173505a1495SSourav Poddar clk_mask = QSPI_CLK_EN | clk_div; 174505a1495SSourav Poddar ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG); 175505a1495SSourav Poddar ctx_reg->clkctrl = clk_mask; 176505a1495SSourav Poddar 177505a1495SSourav Poddar pm_runtime_mark_last_busy(qspi->dev); 178505a1495SSourav Poddar ret = pm_runtime_put_autosuspend(qspi->dev); 179505a1495SSourav Poddar if (ret < 0) { 180505a1495SSourav Poddar dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n"); 181505a1495SSourav Poddar return ret; 182505a1495SSourav Poddar } 183505a1495SSourav Poddar 184505a1495SSourav Poddar return 0; 185505a1495SSourav Poddar } 186505a1495SSourav Poddar 187505a1495SSourav Poddar static void ti_qspi_restore_ctx(struct ti_qspi *qspi) 188505a1495SSourav Poddar { 189505a1495SSourav Poddar struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; 190505a1495SSourav Poddar 191505a1495SSourav Poddar ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG); 192505a1495SSourav Poddar } 193505a1495SSourav Poddar 19400611047SMugunthan V N static inline u32 qspi_is_busy(struct ti_qspi *qspi) 19500611047SMugunthan V N { 19600611047SMugunthan V N u32 stat; 19700611047SMugunthan V N unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; 19800611047SMugunthan V N 19900611047SMugunthan V N stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 20000611047SMugunthan V N while ((stat & BUSY) && time_after(timeout, jiffies)) { 20100611047SMugunthan V N cpu_relax(); 20200611047SMugunthan V N stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 20300611047SMugunthan V N } 20400611047SMugunthan V N 20500611047SMugunthan V N WARN(stat & BUSY, "qspi busy\n"); 20600611047SMugunthan V N return stat & BUSY; 20700611047SMugunthan V N } 20800611047SMugunthan V N 20957c2ecd9SVignesh R static inline int ti_qspi_poll_wc(struct ti_qspi *qspi) 21057c2ecd9SVignesh R { 21157c2ecd9SVignesh R u32 stat; 21257c2ecd9SVignesh R unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT; 21357c2ecd9SVignesh R 21457c2ecd9SVignesh R do { 21557c2ecd9SVignesh R stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 21657c2ecd9SVignesh R if (stat & WC) 21757c2ecd9SVignesh R return 0; 21857c2ecd9SVignesh R cpu_relax(); 21957c2ecd9SVignesh R } while (time_after(timeout, jiffies)); 22057c2ecd9SVignesh R 22157c2ecd9SVignesh R stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 22257c2ecd9SVignesh R if (stat & WC) 22357c2ecd9SVignesh R return 0; 22457c2ecd9SVignesh R return -ETIMEDOUT; 22557c2ecd9SVignesh R } 22657c2ecd9SVignesh R 227505a1495SSourav Poddar static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) 228505a1495SSourav Poddar { 229f682c4ffSVignesh R int wlen, count, xfer_len; 230505a1495SSourav Poddar unsigned int cmd; 231505a1495SSourav Poddar const u8 *txbuf; 232f682c4ffSVignesh R u32 data; 233505a1495SSourav Poddar 234505a1495SSourav Poddar txbuf = t->tx_buf; 235505a1495SSourav Poddar cmd = qspi->cmd | QSPI_WR_SNGL; 236505a1495SSourav Poddar count = t->len; 2373ab54620SAxel Lin wlen = t->bits_per_word >> 3; /* in bytes */ 238f682c4ffSVignesh R xfer_len = wlen; 239505a1495SSourav Poddar 240505a1495SSourav Poddar while (count) { 24100611047SMugunthan V N if (qspi_is_busy(qspi)) 24200611047SMugunthan V N return -EBUSY; 24300611047SMugunthan V N 244505a1495SSourav Poddar switch (wlen) { 2453ab54620SAxel Lin case 1: 246505a1495SSourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", 247505a1495SSourav Poddar cmd, qspi->dc, *txbuf); 248f682c4ffSVignesh R if (count >= QSPI_WLEN_MAX_BYTES) { 249f682c4ffSVignesh R u32 *txp = (u32 *)txbuf; 250f682c4ffSVignesh R 251f682c4ffSVignesh R data = cpu_to_be32(*txp++); 252f682c4ffSVignesh R writel(data, qspi->base + 253f682c4ffSVignesh R QSPI_SPI_DATA_REG_3); 254f682c4ffSVignesh R data = cpu_to_be32(*txp++); 255f682c4ffSVignesh R writel(data, qspi->base + 256f682c4ffSVignesh R QSPI_SPI_DATA_REG_2); 257f682c4ffSVignesh R data = cpu_to_be32(*txp++); 258f682c4ffSVignesh R writel(data, qspi->base + 259f682c4ffSVignesh R QSPI_SPI_DATA_REG_1); 260f682c4ffSVignesh R data = cpu_to_be32(*txp++); 261f682c4ffSVignesh R writel(data, qspi->base + 262f682c4ffSVignesh R QSPI_SPI_DATA_REG); 263f682c4ffSVignesh R xfer_len = QSPI_WLEN_MAX_BYTES; 264f682c4ffSVignesh R cmd |= QSPI_WLEN(QSPI_WLEN_MAX_BITS); 265f682c4ffSVignesh R } else { 266505a1495SSourav Poddar writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); 267f682c4ffSVignesh R cmd = qspi->cmd | QSPI_WR_SNGL; 268f682c4ffSVignesh R xfer_len = wlen; 269f682c4ffSVignesh R cmd |= QSPI_WLEN(wlen); 270f682c4ffSVignesh R } 271505a1495SSourav Poddar break; 2723ab54620SAxel Lin case 2: 273505a1495SSourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", 274505a1495SSourav Poddar cmd, qspi->dc, *txbuf); 275505a1495SSourav Poddar writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); 276505a1495SSourav Poddar break; 2773ab54620SAxel Lin case 4: 278505a1495SSourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", 279505a1495SSourav Poddar cmd, qspi->dc, *txbuf); 280505a1495SSourav Poddar writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); 2813ab54620SAxel Lin break; 2823ab54620SAxel Lin } 2833ab54620SAxel Lin 284505a1495SSourav Poddar ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 28557c2ecd9SVignesh R if (ti_qspi_poll_wc(qspi)) { 286505a1495SSourav Poddar dev_err(qspi->dev, "write timed out\n"); 287505a1495SSourav Poddar return -ETIMEDOUT; 288505a1495SSourav Poddar } 289f682c4ffSVignesh R txbuf += xfer_len; 290f682c4ffSVignesh R count -= xfer_len; 291505a1495SSourav Poddar } 292505a1495SSourav Poddar 293505a1495SSourav Poddar return 0; 294505a1495SSourav Poddar } 295505a1495SSourav Poddar 296505a1495SSourav Poddar static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) 297505a1495SSourav Poddar { 298060556a9SNicholas Mc Guire int wlen, count; 299505a1495SSourav Poddar unsigned int cmd; 300505a1495SSourav Poddar u8 *rxbuf; 301505a1495SSourav Poddar 302505a1495SSourav Poddar rxbuf = t->rx_buf; 30370e2e976SSourav Poddar cmd = qspi->cmd; 30470e2e976SSourav Poddar switch (t->rx_nbits) { 30570e2e976SSourav Poddar case SPI_NBITS_DUAL: 30670e2e976SSourav Poddar cmd |= QSPI_RD_DUAL; 30770e2e976SSourav Poddar break; 30870e2e976SSourav Poddar case SPI_NBITS_QUAD: 30970e2e976SSourav Poddar cmd |= QSPI_RD_QUAD; 31070e2e976SSourav Poddar break; 31170e2e976SSourav Poddar default: 31270e2e976SSourav Poddar cmd |= QSPI_RD_SNGL; 31370e2e976SSourav Poddar break; 31470e2e976SSourav Poddar } 315505a1495SSourav Poddar count = t->len; 3163ab54620SAxel Lin wlen = t->bits_per_word >> 3; /* in bytes */ 317505a1495SSourav Poddar 318505a1495SSourav Poddar while (count) { 319505a1495SSourav Poddar dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); 32000611047SMugunthan V N if (qspi_is_busy(qspi)) 32100611047SMugunthan V N return -EBUSY; 32200611047SMugunthan V N 323505a1495SSourav Poddar ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 32457c2ecd9SVignesh R if (ti_qspi_poll_wc(qspi)) { 325505a1495SSourav Poddar dev_err(qspi->dev, "read timed out\n"); 326505a1495SSourav Poddar return -ETIMEDOUT; 327505a1495SSourav Poddar } 328505a1495SSourav Poddar switch (wlen) { 3293ab54620SAxel Lin case 1: 330505a1495SSourav Poddar *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); 331505a1495SSourav Poddar break; 3323ab54620SAxel Lin case 2: 333505a1495SSourav Poddar *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); 334505a1495SSourav Poddar break; 3353ab54620SAxel Lin case 4: 336505a1495SSourav Poddar *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); 337505a1495SSourav Poddar break; 338505a1495SSourav Poddar } 3393ab54620SAxel Lin rxbuf += wlen; 3403ab54620SAxel Lin count -= wlen; 341505a1495SSourav Poddar } 342505a1495SSourav Poddar 343505a1495SSourav Poddar return 0; 344505a1495SSourav Poddar } 345505a1495SSourav Poddar 346505a1495SSourav Poddar static int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) 347505a1495SSourav Poddar { 348505a1495SSourav Poddar int ret; 349505a1495SSourav Poddar 350505a1495SSourav Poddar if (t->tx_buf) { 351505a1495SSourav Poddar ret = qspi_write_msg(qspi, t); 352505a1495SSourav Poddar if (ret) { 353505a1495SSourav Poddar dev_dbg(qspi->dev, "Error while writing\n"); 354505a1495SSourav Poddar return ret; 355505a1495SSourav Poddar } 356505a1495SSourav Poddar } 357505a1495SSourav Poddar 358505a1495SSourav Poddar if (t->rx_buf) { 359505a1495SSourav Poddar ret = qspi_read_msg(qspi, t); 360505a1495SSourav Poddar if (ret) { 361505a1495SSourav Poddar dev_dbg(qspi->dev, "Error while reading\n"); 362505a1495SSourav Poddar return ret; 363505a1495SSourav Poddar } 364505a1495SSourav Poddar } 365505a1495SSourav Poddar 366505a1495SSourav Poddar return 0; 367505a1495SSourav Poddar } 368505a1495SSourav Poddar 369505a1495SSourav Poddar static int ti_qspi_start_transfer_one(struct spi_master *master, 370505a1495SSourav Poddar struct spi_message *m) 371505a1495SSourav Poddar { 372505a1495SSourav Poddar struct ti_qspi *qspi = spi_master_get_devdata(master); 373505a1495SSourav Poddar struct spi_device *spi = m->spi; 374505a1495SSourav Poddar struct spi_transfer *t; 375505a1495SSourav Poddar int status = 0, ret; 376505a1495SSourav Poddar int frame_length; 377505a1495SSourav Poddar 378505a1495SSourav Poddar /* setup device control reg */ 379505a1495SSourav Poddar qspi->dc = 0; 380505a1495SSourav Poddar 381505a1495SSourav Poddar if (spi->mode & SPI_CPHA) 382505a1495SSourav Poddar qspi->dc |= QSPI_CKPHA(spi->chip_select); 383505a1495SSourav Poddar if (spi->mode & SPI_CPOL) 384505a1495SSourav Poddar qspi->dc |= QSPI_CKPOL(spi->chip_select); 385505a1495SSourav Poddar if (spi->mode & SPI_CS_HIGH) 386505a1495SSourav Poddar qspi->dc |= QSPI_CSPOL(spi->chip_select); 387505a1495SSourav Poddar 388505a1495SSourav Poddar frame_length = (m->frame_length << 3) / spi->bits_per_word; 389505a1495SSourav Poddar 390505a1495SSourav Poddar frame_length = clamp(frame_length, 0, QSPI_FRAME); 391505a1495SSourav Poddar 392505a1495SSourav Poddar /* setup command reg */ 393505a1495SSourav Poddar qspi->cmd = 0; 394505a1495SSourav Poddar qspi->cmd |= QSPI_EN_CS(spi->chip_select); 395505a1495SSourav Poddar qspi->cmd |= QSPI_FLEN(frame_length); 396505a1495SSourav Poddar 397505a1495SSourav Poddar ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG); 398505a1495SSourav Poddar 399505a1495SSourav Poddar mutex_lock(&qspi->list_lock); 400505a1495SSourav Poddar 401505a1495SSourav Poddar list_for_each_entry(t, &m->transfers, transfer_list) { 402505a1495SSourav Poddar qspi->cmd |= QSPI_WLEN(t->bits_per_word); 403505a1495SSourav Poddar 404505a1495SSourav Poddar ret = qspi_transfer_msg(qspi, t); 405505a1495SSourav Poddar if (ret) { 406505a1495SSourav Poddar dev_dbg(qspi->dev, "transfer message failed\n"); 407b6460366SWei Yongjun mutex_unlock(&qspi->list_lock); 408505a1495SSourav Poddar return -EINVAL; 409505a1495SSourav Poddar } 410505a1495SSourav Poddar 411505a1495SSourav Poddar m->actual_length += t->len; 412505a1495SSourav Poddar } 413505a1495SSourav Poddar 414505a1495SSourav Poddar mutex_unlock(&qspi->list_lock); 415505a1495SSourav Poddar 416bc27a539SVignesh R ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); 417505a1495SSourav Poddar m->status = status; 418505a1495SSourav Poddar spi_finalize_current_message(master); 419505a1495SSourav Poddar 420505a1495SSourav Poddar return status; 421505a1495SSourav Poddar } 422505a1495SSourav Poddar 423505a1495SSourav Poddar static int ti_qspi_runtime_resume(struct device *dev) 424505a1495SSourav Poddar { 425505a1495SSourav Poddar struct ti_qspi *qspi; 426505a1495SSourav Poddar 427f17414c4SSourav Poddar qspi = dev_get_drvdata(dev); 428505a1495SSourav Poddar ti_qspi_restore_ctx(qspi); 429505a1495SSourav Poddar 430505a1495SSourav Poddar return 0; 431505a1495SSourav Poddar } 432505a1495SSourav Poddar 433505a1495SSourav Poddar static const struct of_device_id ti_qspi_match[] = { 434505a1495SSourav Poddar {.compatible = "ti,dra7xxx-qspi" }, 43509222fc3SSourav Poddar {.compatible = "ti,am4372-qspi" }, 436505a1495SSourav Poddar {}, 437505a1495SSourav Poddar }; 438e1432d30SSourav Poddar MODULE_DEVICE_TABLE(of, ti_qspi_match); 439505a1495SSourav Poddar 440505a1495SSourav Poddar static int ti_qspi_probe(struct platform_device *pdev) 441505a1495SSourav Poddar { 442505a1495SSourav Poddar struct ti_qspi *qspi; 443505a1495SSourav Poddar struct spi_master *master; 4446b3938aeSSourav Poddar struct resource *r, *res_ctrl, *res_mmap; 445505a1495SSourav Poddar struct device_node *np = pdev->dev.of_node; 446505a1495SSourav Poddar u32 max_freq; 447505a1495SSourav Poddar int ret = 0, num_cs, irq; 448505a1495SSourav Poddar 449505a1495SSourav Poddar master = spi_alloc_master(&pdev->dev, sizeof(*qspi)); 450505a1495SSourav Poddar if (!master) 451505a1495SSourav Poddar return -ENOMEM; 452505a1495SSourav Poddar 453633795b9SSourav Poddar master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; 454505a1495SSourav Poddar 455505a1495SSourav Poddar master->flags = SPI_MASTER_HALF_DUPLEX; 456505a1495SSourav Poddar master->setup = ti_qspi_setup; 457505a1495SSourav Poddar master->auto_runtime_pm = true; 458505a1495SSourav Poddar master->transfer_one_message = ti_qspi_start_transfer_one; 459505a1495SSourav Poddar master->dev.of_node = pdev->dev.of_node; 460aa188f90SAxel Lin master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | 461aa188f90SAxel Lin SPI_BPW_MASK(8); 462505a1495SSourav Poddar 463505a1495SSourav Poddar if (!of_property_read_u32(np, "num-cs", &num_cs)) 464505a1495SSourav Poddar master->num_chipselect = num_cs; 465505a1495SSourav Poddar 466505a1495SSourav Poddar qspi = spi_master_get_devdata(master); 467505a1495SSourav Poddar qspi->master = master; 468505a1495SSourav Poddar qspi->dev = &pdev->dev; 469160a0613SWei Yongjun platform_set_drvdata(pdev, qspi); 470505a1495SSourav Poddar 4716b3938aeSSourav Poddar r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base"); 4726b3938aeSSourav Poddar if (r == NULL) { 473505a1495SSourav Poddar r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4746b3938aeSSourav Poddar if (r == NULL) { 4756b3938aeSSourav Poddar dev_err(&pdev->dev, "missing platform data\n"); 4766b3938aeSSourav Poddar return -ENODEV; 4776b3938aeSSourav Poddar } 4786b3938aeSSourav Poddar } 4796b3938aeSSourav Poddar 4806b3938aeSSourav Poddar res_mmap = platform_get_resource_byname(pdev, 4816b3938aeSSourav Poddar IORESOURCE_MEM, "qspi_mmap"); 4826b3938aeSSourav Poddar if (res_mmap == NULL) { 4836b3938aeSSourav Poddar res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1); 4846b3938aeSSourav Poddar if (res_mmap == NULL) { 4856b3938aeSSourav Poddar dev_err(&pdev->dev, 4866b3938aeSSourav Poddar "memory mapped resource not required\n"); 4876b3938aeSSourav Poddar } 4886b3938aeSSourav Poddar } 4896b3938aeSSourav Poddar 4906b3938aeSSourav Poddar res_ctrl = platform_get_resource_byname(pdev, 4916b3938aeSSourav Poddar IORESOURCE_MEM, "qspi_ctrlmod"); 4926b3938aeSSourav Poddar if (res_ctrl == NULL) { 4936b3938aeSSourav Poddar res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2); 4946b3938aeSSourav Poddar if (res_ctrl == NULL) { 4956b3938aeSSourav Poddar dev_dbg(&pdev->dev, 4966b3938aeSSourav Poddar "control module resources not required\n"); 4976b3938aeSSourav Poddar } 4986b3938aeSSourav Poddar } 499505a1495SSourav Poddar 500505a1495SSourav Poddar irq = platform_get_irq(pdev, 0); 501505a1495SSourav Poddar if (irq < 0) { 502505a1495SSourav Poddar dev_err(&pdev->dev, "no irq resource?\n"); 503505a1495SSourav Poddar return irq; 504505a1495SSourav Poddar } 505505a1495SSourav Poddar 506505a1495SSourav Poddar mutex_init(&qspi->list_lock); 507505a1495SSourav Poddar 508505a1495SSourav Poddar qspi->base = devm_ioremap_resource(&pdev->dev, r); 509505a1495SSourav Poddar if (IS_ERR(qspi->base)) { 510505a1495SSourav Poddar ret = PTR_ERR(qspi->base); 511505a1495SSourav Poddar goto free_master; 512505a1495SSourav Poddar } 513505a1495SSourav Poddar 5146b3938aeSSourav Poddar if (res_ctrl) { 5156b3938aeSSourav Poddar qspi->ctrl_mod = true; 5166b3938aeSSourav Poddar qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); 5176b3938aeSSourav Poddar if (IS_ERR(qspi->ctrl_base)) { 5186b3938aeSSourav Poddar ret = PTR_ERR(qspi->ctrl_base); 5196b3938aeSSourav Poddar goto free_master; 5206b3938aeSSourav Poddar } 5216b3938aeSSourav Poddar } 5226b3938aeSSourav Poddar 5236b3938aeSSourav Poddar if (res_mmap) { 5246b3938aeSSourav Poddar qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); 5256b3938aeSSourav Poddar if (IS_ERR(qspi->mmap_base)) { 5266b3938aeSSourav Poddar ret = PTR_ERR(qspi->mmap_base); 5276b3938aeSSourav Poddar goto free_master; 5286b3938aeSSourav Poddar } 5296b3938aeSSourav Poddar } 5306b3938aeSSourav Poddar 531505a1495SSourav Poddar qspi->fclk = devm_clk_get(&pdev->dev, "fck"); 532505a1495SSourav Poddar if (IS_ERR(qspi->fclk)) { 533505a1495SSourav Poddar ret = PTR_ERR(qspi->fclk); 534505a1495SSourav Poddar dev_err(&pdev->dev, "could not get clk: %d\n", ret); 535505a1495SSourav Poddar } 536505a1495SSourav Poddar 537505a1495SSourav Poddar pm_runtime_use_autosuspend(&pdev->dev); 538505a1495SSourav Poddar pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT); 539505a1495SSourav Poddar pm_runtime_enable(&pdev->dev); 540505a1495SSourav Poddar 541505a1495SSourav Poddar if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) 542505a1495SSourav Poddar qspi->spi_max_frequency = max_freq; 543505a1495SSourav Poddar 5447388c03bSJingoo Han ret = devm_spi_register_master(&pdev->dev, master); 545505a1495SSourav Poddar if (ret) 546505a1495SSourav Poddar goto free_master; 547505a1495SSourav Poddar 548505a1495SSourav Poddar return 0; 549505a1495SSourav Poddar 550505a1495SSourav Poddar free_master: 551505a1495SSourav Poddar spi_master_put(master); 552505a1495SSourav Poddar return ret; 553505a1495SSourav Poddar } 554505a1495SSourav Poddar 555505a1495SSourav Poddar static int ti_qspi_remove(struct platform_device *pdev) 556505a1495SSourav Poddar { 557e6b5140bSFelipe Balbi pm_runtime_put_sync(&pdev->dev); 558cbcabb7aSSourav Poddar pm_runtime_disable(&pdev->dev); 559cbcabb7aSSourav Poddar 560505a1495SSourav Poddar return 0; 561505a1495SSourav Poddar } 562505a1495SSourav Poddar 563505a1495SSourav Poddar static const struct dev_pm_ops ti_qspi_pm_ops = { 564505a1495SSourav Poddar .runtime_resume = ti_qspi_runtime_resume, 565505a1495SSourav Poddar }; 566505a1495SSourav Poddar 567505a1495SSourav Poddar static struct platform_driver ti_qspi_driver = { 568505a1495SSourav Poddar .probe = ti_qspi_probe, 569505a1495SSourav Poddar .remove = ti_qspi_remove, 570505a1495SSourav Poddar .driver = { 5715a33d30fSAxel Lin .name = "ti-qspi", 572505a1495SSourav Poddar .pm = &ti_qspi_pm_ops, 573505a1495SSourav Poddar .of_match_table = ti_qspi_match, 574505a1495SSourav Poddar } 575505a1495SSourav Poddar }; 576505a1495SSourav Poddar 577505a1495SSourav Poddar module_platform_driver(ti_qspi_driver); 578505a1495SSourav Poddar 579505a1495SSourav Poddar MODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); 580505a1495SSourav Poddar MODULE_LICENSE("GPL v2"); 581505a1495SSourav Poddar MODULE_DESCRIPTION("TI QSPI controller driver"); 5825a33d30fSAxel Lin MODULE_ALIAS("platform:ti-qspi"); 583