1505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar/* 2505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * TI QSPI driver 3505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * 4505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com 5505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * Author: Sourav Poddar <sourav.poddar@ti.com> 6505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * 7505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * This program is free software; you can redistribute it and/or 8505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * modify it under the terms of the GPLv2. 9505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * 10505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * This program is distributed in the hope that it will be useful, 11505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * but WITHOUT ANY WARRANTY; without even the implied warranty of 12505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the 13505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar * GNU General Public License for more details. 14505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar */ 15505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 16505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/kernel.h> 17505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/init.h> 18505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/interrupt.h> 19505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/module.h> 20505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/device.h> 21505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/delay.h> 22505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/dma-mapping.h> 23505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/dmaengine.h> 24505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/omap-dma.h> 25505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/platform_device.h> 26505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/err.h> 27505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/clk.h> 28505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/io.h> 29505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/slab.h> 30505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/pm_runtime.h> 31505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/of.h> 32505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/of_device.h> 33505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/pinctrl/consumer.h> 34505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 35505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#include <linux/spi/spi.h> 36505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 37505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstruct ti_qspi_regs { 38505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u32 clkctrl; 39505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar}; 40505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 41505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstruct ti_qspi { 42505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct completion transfer_complete; 43505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 44505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar /* list synchronization */ 45505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct mutex list_lock; 46505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 47505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct spi_master *master; 48505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar void __iomem *base; 496b3938aed04587dab42f9df83122a40c596f495aSourav Poddar void __iomem *ctrl_base; 506b3938aed04587dab42f9df83122a40c596f495aSourav Poddar void __iomem *mmap_base; 51505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct clk *fclk; 52505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct device *dev; 53505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 54505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi_regs ctx_reg; 55505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 56505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u32 spi_max_frequency; 57505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u32 cmd; 58505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u32 dc; 596b3938aed04587dab42f9df83122a40c596f495aSourav Poddar 606b3938aed04587dab42f9df83122a40c596f495aSourav Poddar bool ctrl_mod; 61505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar}; 62505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 63505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_PID (0x0) 64505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SYSCONFIG (0x10) 65505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_INTR_STATUS_RAW_SET (0x20) 66505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_INTR_STATUS_ENABLED_CLEAR (0x24) 67505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_INTR_ENABLE_SET_REG (0x28) 68505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_INTR_ENABLE_CLEAR_REG (0x2c) 69505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_CLOCK_CNTRL_REG (0x40) 70505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_DC_REG (0x44) 71505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_CMD_REG (0x48) 72505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_STATUS_REG (0x4c) 73505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_DATA_REG (0x50) 74505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_SETUP0_REG (0x54) 75505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_SWITCH_REG (0x64) 76505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_SETUP1_REG (0x58) 77505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_SETUP2_REG (0x5c) 78505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_SETUP3_REG (0x60) 79505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_DATA_REG_1 (0x68) 80505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_DATA_REG_2 (0x6c) 81505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_SPI_DATA_REG_3 (0x70) 82505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 83505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000) 84505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 85505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_FCLK 192000000 86505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 87505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar/* Clock Control */ 88505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_CLK_EN (1 << 31) 89505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_CLK_DIV_MAX 0xffff 90505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 91505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar/* Command */ 92505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_EN_CS(n) (n << 28) 93505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_WLEN(n) ((n - 1) << 19) 94505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_3_PIN (1 << 18) 95505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_RD_SNGL (1 << 16) 96505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_WR_SNGL (2 << 16) 97505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_RD_DUAL (3 << 16) 98505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_RD_QUAD (7 << 16) 99505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_INVAL (4 << 16) 100505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_WC_CMD_INT_EN (1 << 14) 101505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_FLEN(n) ((n - 1) << 0) 102505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 103505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar/* STATUS REGISTER */ 104505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define WC 0x02 105505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 106505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar/* INTERRUPT REGISTER */ 107505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_WC_INT_EN (1 << 1) 108505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_WC_INT_DISABLE (1 << 1) 109505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 110505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar/* Device Control */ 111505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_DD(m, n) (m << (3 + n * 8)) 112505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_CKPHA(n) (1 << (2 + n * 8)) 113505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_CSPOL(n) (1 << (1 + n * 8)) 114505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_CKPOL(n) (1 << (n * 8)) 115505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 116505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_FRAME 4096 117505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 118505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar#define QSPI_AUTOSUSPEND_TIMEOUT 2000 119505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 120505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic inline unsigned long ti_qspi_read(struct ti_qspi *qspi, 121505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar unsigned long reg) 122505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 123505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return readl(qspi->base + reg); 124505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 125505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 126505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic inline void ti_qspi_write(struct ti_qspi *qspi, 127505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar unsigned long val, unsigned long reg) 128505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 129505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar writel(val, qspi->base + reg); 130505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 131505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 132505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int ti_qspi_setup(struct spi_device *spi) 133505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 134505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi *qspi = spi_master_get_devdata(spi->master); 135505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; 136505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int clk_div = 0, ret; 137505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u32 clk_ctrl_reg, clk_rate, clk_mask; 138505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 139505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (spi->master->busy) { 140505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "master busy doing other trasnfers\n"); 141505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return -EBUSY; 142505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 143505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 144505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (!qspi->spi_max_frequency) { 145505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_err(qspi->dev, "spi max frequency not defined\n"); 146505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return -EINVAL; 147505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 148505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 149505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar clk_rate = clk_get_rate(qspi->fclk); 150505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 151505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar clk_div = DIV_ROUND_UP(clk_rate, qspi->spi_max_frequency) - 1; 152505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 153505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (clk_div < 0) { 154505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "clock divider < 0, using /1 divider\n"); 155505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return -EINVAL; 156505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 157505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 158505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (clk_div > QSPI_CLK_DIV_MAX) { 159505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "clock divider >%d , using /%d divider\n", 160505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1); 161505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return -EINVAL; 162505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 163505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 164505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "hz: %d, clock divider %d\n", 165505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->spi_max_frequency, clk_div); 166505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 167505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = pm_runtime_get_sync(qspi->dev); 16805b96675dbfc97fbb66d58cacbf2c8def020375eSourav Poddar if (ret < 0) { 169505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); 170505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return ret; 171505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 172505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 173505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar clk_ctrl_reg = ti_qspi_read(qspi, QSPI_SPI_CLOCK_CNTRL_REG); 174505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 175505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar clk_ctrl_reg &= ~QSPI_CLK_EN; 176505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 177505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar /* disable SCLK */ 178505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, clk_ctrl_reg, QSPI_SPI_CLOCK_CNTRL_REG); 179505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 180505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar /* enable SCLK */ 181505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar clk_mask = QSPI_CLK_EN | clk_div; 182505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, clk_mask, QSPI_SPI_CLOCK_CNTRL_REG); 183505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ctx_reg->clkctrl = clk_mask; 184505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 185505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar pm_runtime_mark_last_busy(qspi->dev); 186505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = pm_runtime_put_autosuspend(qspi->dev); 187505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (ret < 0) { 188505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_err(qspi->dev, "pm_runtime_put_autosuspend() failed\n"); 189505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return ret; 190505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 191505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 192505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return 0; 193505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 194505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 195505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic void ti_qspi_restore_ctx(struct ti_qspi *qspi) 196505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 197505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi_regs *ctx_reg = &qspi->ctx_reg; 198505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 199505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, ctx_reg->clkctrl, QSPI_SPI_CLOCK_CNTRL_REG); 200505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 201505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 202505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t) 203505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 204505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int wlen, count, ret; 205505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar unsigned int cmd; 206505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar const u8 *txbuf; 207505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 208505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar txbuf = t->tx_buf; 209505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar cmd = qspi->cmd | QSPI_WR_SNGL; 210505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar count = t->len; 2113ab546205411a245ef0f60ec708467a072855c6fAxel Lin wlen = t->bits_per_word >> 3; /* in bytes */ 212505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 213505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar while (count) { 214505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar switch (wlen) { 2153ab546205411a245ef0f60ec708467a072855c6fAxel Lin case 1: 216505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %02x\n", 217505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar cmd, qspi->dc, *txbuf); 218505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar writeb(*txbuf, qspi->base + QSPI_SPI_DATA_REG); 219505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar break; 2203ab546205411a245ef0f60ec708467a072855c6fAxel Lin case 2: 221505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %04x\n", 222505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar cmd, qspi->dc, *txbuf); 223505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar writew(*((u16 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); 224505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar break; 2253ab546205411a245ef0f60ec708467a072855c6fAxel Lin case 4: 226505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "tx cmd %08x dc %08x data %08x\n", 227505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar cmd, qspi->dc, *txbuf); 228505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar writel(*((u32 *)txbuf), qspi->base + QSPI_SPI_DATA_REG); 229505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar break; 230505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 2313ab546205411a245ef0f60ec708467a072855c6fAxel Lin 2323ab546205411a245ef0f60ec708467a072855c6fAxel Lin ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 2333ab546205411a245ef0f60ec708467a072855c6fAxel Lin ret = wait_for_completion_timeout(&qspi->transfer_complete, 2343ab546205411a245ef0f60ec708467a072855c6fAxel Lin QSPI_COMPLETION_TIMEOUT); 2353ab546205411a245ef0f60ec708467a072855c6fAxel Lin if (ret == 0) { 2363ab546205411a245ef0f60ec708467a072855c6fAxel Lin dev_err(qspi->dev, "write timed out\n"); 2373ab546205411a245ef0f60ec708467a072855c6fAxel Lin return -ETIMEDOUT; 2383ab546205411a245ef0f60ec708467a072855c6fAxel Lin } 2393ab546205411a245ef0f60ec708467a072855c6fAxel Lin txbuf += wlen; 2403ab546205411a245ef0f60ec708467a072855c6fAxel Lin count -= wlen; 241505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 242505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 243505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return 0; 244505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 245505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 246505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t) 247505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 248505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int wlen, count, ret; 249505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar unsigned int cmd; 250505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u8 *rxbuf; 251505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 252505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar rxbuf = t->rx_buf; 25370e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar cmd = qspi->cmd; 25470e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar switch (t->rx_nbits) { 25570e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar case SPI_NBITS_DUAL: 25670e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar cmd |= QSPI_RD_DUAL; 25770e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar break; 25870e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar case SPI_NBITS_QUAD: 25970e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar cmd |= QSPI_RD_QUAD; 26070e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar break; 26170e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar default: 26270e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar cmd |= QSPI_RD_SNGL; 26370e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar break; 26470e2e9761a580cc9ef84be69dac2279dd6c2c72fSourav Poddar } 265505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar count = t->len; 2663ab546205411a245ef0f60ec708467a072855c6fAxel Lin wlen = t->bits_per_word >> 3; /* in bytes */ 267505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 268505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar while (count) { 269505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc); 270505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG); 271505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = wait_for_completion_timeout(&qspi->transfer_complete, 272505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar QSPI_COMPLETION_TIMEOUT); 273505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (ret == 0) { 274505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_err(qspi->dev, "read timed out\n"); 275505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return -ETIMEDOUT; 276505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 277505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar switch (wlen) { 2783ab546205411a245ef0f60ec708467a072855c6fAxel Lin case 1: 279505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar *rxbuf = readb(qspi->base + QSPI_SPI_DATA_REG); 280505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar break; 2813ab546205411a245ef0f60ec708467a072855c6fAxel Lin case 2: 282505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar *((u16 *)rxbuf) = readw(qspi->base + QSPI_SPI_DATA_REG); 283505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar break; 2843ab546205411a245ef0f60ec708467a072855c6fAxel Lin case 4: 285505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar *((u32 *)rxbuf) = readl(qspi->base + QSPI_SPI_DATA_REG); 286505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar break; 287505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 2883ab546205411a245ef0f60ec708467a072855c6fAxel Lin rxbuf += wlen; 2893ab546205411a245ef0f60ec708467a072855c6fAxel Lin count -= wlen; 290505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 291505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 292505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return 0; 293505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 294505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 295505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int qspi_transfer_msg(struct ti_qspi *qspi, struct spi_transfer *t) 296505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 297505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int ret; 298505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 299505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (t->tx_buf) { 300505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = qspi_write_msg(qspi, t); 301505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (ret) { 302505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "Error while writing\n"); 303505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return ret; 304505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 305505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 306505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 307505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (t->rx_buf) { 308505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = qspi_read_msg(qspi, t); 309505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (ret) { 310505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "Error while reading\n"); 311505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return ret; 312505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 313505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 314505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 315505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return 0; 316505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 317505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 318505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int ti_qspi_start_transfer_one(struct spi_master *master, 319505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct spi_message *m) 320505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 321505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi *qspi = spi_master_get_devdata(master); 322505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct spi_device *spi = m->spi; 323505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct spi_transfer *t; 324505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int status = 0, ret; 325505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int frame_length; 326505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 327505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar /* setup device control reg */ 328505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->dc = 0; 329505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 330505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (spi->mode & SPI_CPHA) 331505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->dc |= QSPI_CKPHA(spi->chip_select); 332505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (spi->mode & SPI_CPOL) 333505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->dc |= QSPI_CKPOL(spi->chip_select); 334505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (spi->mode & SPI_CS_HIGH) 335505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->dc |= QSPI_CSPOL(spi->chip_select); 336505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 337505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar frame_length = (m->frame_length << 3) / spi->bits_per_word; 338505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 339505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar frame_length = clamp(frame_length, 0, QSPI_FRAME); 340505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 341505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar /* setup command reg */ 342505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->cmd = 0; 343505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->cmd |= QSPI_EN_CS(spi->chip_select); 344505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->cmd |= QSPI_FLEN(frame_length); 345505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->cmd |= QSPI_WC_CMD_INT_EN; 346505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 347505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, QSPI_WC_INT_EN, QSPI_INTR_ENABLE_SET_REG); 348505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, qspi->dc, QSPI_SPI_DC_REG); 349505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 350505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar mutex_lock(&qspi->list_lock); 351505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 352505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar list_for_each_entry(t, &m->transfers, transfer_list) { 353505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->cmd |= QSPI_WLEN(t->bits_per_word); 354505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 355505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = qspi_transfer_msg(qspi, t); 356505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (ret) { 357505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "transfer message failed\n"); 358b6460366fbadc160604f50047d0394c7fc39ceabWei Yongjun mutex_unlock(&qspi->list_lock); 359505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return -EINVAL; 360505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 361505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 362505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar m->actual_length += t->len; 363505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 364505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 365505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar mutex_unlock(&qspi->list_lock); 366505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 367505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar m->status = status; 368505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar spi_finalize_current_message(master); 369505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 370505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, qspi->cmd | QSPI_INVAL, QSPI_SPI_CMD_REG); 371505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 372505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return status; 373505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 374505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 375505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic irqreturn_t ti_qspi_isr(int irq, void *dev_id) 376505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 377505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi *qspi = dev_id; 378505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u16 int_stat; 3793b3a80019ff194e86e740ec2f013a8915efd1ccfSebastian Andrzej Siewior u32 stat; 380505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 381505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar irqreturn_t ret = IRQ_HANDLED; 382505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 383505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int_stat = ti_qspi_read(qspi, QSPI_INTR_STATUS_ENABLED_CLEAR); 3843b3a80019ff194e86e740ec2f013a8915efd1ccfSebastian Andrzej Siewior stat = ti_qspi_read(qspi, QSPI_SPI_STATUS_REG); 385505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 386505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (!int_stat) { 387505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_dbg(qspi->dev, "No IRQ triggered\n"); 388505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = IRQ_NONE; 389505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar goto out; 390505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 391505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 392505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, 393505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar QSPI_INTR_STATUS_ENABLED_CLEAR); 3943b3a80019ff194e86e740ec2f013a8915efd1ccfSebastian Andrzej Siewior if (stat & WC) 3953b3a80019ff194e86e740ec2f013a8915efd1ccfSebastian Andrzej Siewior complete(&qspi->transfer_complete); 396505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarout: 397505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return ret; 398505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 399505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 400505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int ti_qspi_runtime_resume(struct device *dev) 401505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 402505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi *qspi; 403505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 404f17414c4fcf138740dbbd463171101026b6f78deSourav Poddar qspi = dev_get_drvdata(dev); 405505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ti_qspi_restore_ctx(qspi); 406505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 407505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return 0; 408505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 409505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 410505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic const struct of_device_id ti_qspi_match[] = { 411505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar {.compatible = "ti,dra7xxx-qspi" }, 41209222fc33f8e22e81d34a7518e6dd120e4128a11Sourav Poddar {.compatible = "ti,am4372-qspi" }, 413505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar {}, 414505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar}; 415e1432d30cb245f562d495043a58476e7c3b4358eSourav PoddarMODULE_DEVICE_TABLE(of, ti_qspi_match); 416505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 417505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int ti_qspi_probe(struct platform_device *pdev) 418505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 419505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct ti_qspi *qspi; 420505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct spi_master *master; 4216b3938aed04587dab42f9df83122a40c596f495aSourav Poddar struct resource *r, *res_ctrl, *res_mmap; 422505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar struct device_node *np = pdev->dev.of_node; 423505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar u32 max_freq; 424505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar int ret = 0, num_cs, irq; 425505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 426505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar master = spi_alloc_master(&pdev->dev, sizeof(*qspi)); 427505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (!master) 428505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return -ENOMEM; 429505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 430633795b992ebae2a78890c0cfa5c17058eb93817Sourav Poddar master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD; 431505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 432505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar master->flags = SPI_MASTER_HALF_DUPLEX; 433505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar master->setup = ti_qspi_setup; 434505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar master->auto_runtime_pm = true; 435505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar master->transfer_one_message = ti_qspi_start_transfer_one; 436505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar master->dev.of_node = pdev->dev.of_node; 437aa188f90ff1a82fa8f848092ff4969dba78b275fAxel Lin master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(16) | 438aa188f90ff1a82fa8f848092ff4969dba78b275fAxel Lin SPI_BPW_MASK(8); 439505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 440505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (!of_property_read_u32(np, "num-cs", &num_cs)) 441505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar master->num_chipselect = num_cs; 442505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 443505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi = spi_master_get_devdata(master); 444505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->master = master; 445505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->dev = &pdev->dev; 446160a061301c7adf54c40696e7ceedc73f6b747ddWei Yongjun platform_set_drvdata(pdev, qspi); 447505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 4486b3938aed04587dab42f9df83122a40c596f495aSourav Poddar r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_base"); 4496b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (r == NULL) { 4506b3938aed04587dab42f9df83122a40c596f495aSourav Poddar r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 4516b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (r == NULL) { 4526b3938aed04587dab42f9df83122a40c596f495aSourav Poddar dev_err(&pdev->dev, "missing platform data\n"); 4536b3938aed04587dab42f9df83122a40c596f495aSourav Poddar return -ENODEV; 4546b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 4556b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 456505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 4576b3938aed04587dab42f9df83122a40c596f495aSourav Poddar res_mmap = platform_get_resource_byname(pdev, 4586b3938aed04587dab42f9df83122a40c596f495aSourav Poddar IORESOURCE_MEM, "qspi_mmap"); 4596b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (res_mmap == NULL) { 4606b3938aed04587dab42f9df83122a40c596f495aSourav Poddar res_mmap = platform_get_resource(pdev, IORESOURCE_MEM, 1); 4616b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (res_mmap == NULL) { 4626b3938aed04587dab42f9df83122a40c596f495aSourav Poddar dev_err(&pdev->dev, 4636b3938aed04587dab42f9df83122a40c596f495aSourav Poddar "memory mapped resource not required\n"); 4646b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 4656b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 4666b3938aed04587dab42f9df83122a40c596f495aSourav Poddar 4676b3938aed04587dab42f9df83122a40c596f495aSourav Poddar res_ctrl = platform_get_resource_byname(pdev, 4686b3938aed04587dab42f9df83122a40c596f495aSourav Poddar IORESOURCE_MEM, "qspi_ctrlmod"); 4696b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (res_ctrl == NULL) { 4706b3938aed04587dab42f9df83122a40c596f495aSourav Poddar res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 2); 4716b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (res_ctrl == NULL) { 4726b3938aed04587dab42f9df83122a40c596f495aSourav Poddar dev_dbg(&pdev->dev, 4736b3938aed04587dab42f9df83122a40c596f495aSourav Poddar "control module resources not required\n"); 4746b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 4756b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 476505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 477505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar irq = platform_get_irq(pdev, 0); 478505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (irq < 0) { 479505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_err(&pdev->dev, "no irq resource?\n"); 480505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return irq; 481505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 482505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 483505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar mutex_init(&qspi->list_lock); 484505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 485505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->base = devm_ioremap_resource(&pdev->dev, r); 486505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (IS_ERR(qspi->base)) { 487505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = PTR_ERR(qspi->base); 488505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar goto free_master; 489505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 490505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 4916b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (res_ctrl) { 4926b3938aed04587dab42f9df83122a40c596f495aSourav Poddar qspi->ctrl_mod = true; 4936b3938aed04587dab42f9df83122a40c596f495aSourav Poddar qspi->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); 4946b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (IS_ERR(qspi->ctrl_base)) { 4956b3938aed04587dab42f9df83122a40c596f495aSourav Poddar ret = PTR_ERR(qspi->ctrl_base); 4966b3938aed04587dab42f9df83122a40c596f495aSourav Poddar goto free_master; 4976b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 4986b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 4996b3938aed04587dab42f9df83122a40c596f495aSourav Poddar 5006b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (res_mmap) { 5016b3938aed04587dab42f9df83122a40c596f495aSourav Poddar qspi->mmap_base = devm_ioremap_resource(&pdev->dev, res_mmap); 5026b3938aed04587dab42f9df83122a40c596f495aSourav Poddar if (IS_ERR(qspi->mmap_base)) { 5036b3938aed04587dab42f9df83122a40c596f495aSourav Poddar ret = PTR_ERR(qspi->mmap_base); 5046b3938aed04587dab42f9df83122a40c596f495aSourav Poddar goto free_master; 5056b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 5066b3938aed04587dab42f9df83122a40c596f495aSourav Poddar } 5076b3938aed04587dab42f9df83122a40c596f495aSourav Poddar 5083b3a80019ff194e86e740ec2f013a8915efd1ccfSebastian Andrzej Siewior ret = devm_request_irq(&pdev->dev, irq, ti_qspi_isr, 0, 509505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_name(&pdev->dev), qspi); 510505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (ret < 0) { 511505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", 512505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar irq); 513505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar goto free_master; 514505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 515505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 516505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->fclk = devm_clk_get(&pdev->dev, "fck"); 517505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (IS_ERR(qspi->fclk)) { 518505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar ret = PTR_ERR(qspi->fclk); 519505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar dev_err(&pdev->dev, "could not get clk: %d\n", ret); 520505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 521505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 522505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar init_completion(&qspi->transfer_complete); 523505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 524505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar pm_runtime_use_autosuspend(&pdev->dev); 525505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar pm_runtime_set_autosuspend_delay(&pdev->dev, QSPI_AUTOSUSPEND_TIMEOUT); 526505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar pm_runtime_enable(&pdev->dev); 527505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 528505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (!of_property_read_u32(np, "spi-max-frequency", &max_freq)) 529505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar qspi->spi_max_frequency = max_freq; 530505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 5317388c03bac1b4466864945233abf3ca8ba1cb061Jingoo Han ret = devm_spi_register_master(&pdev->dev, master); 532505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar if (ret) 533505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar goto free_master; 534505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 535505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return 0; 536505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 537505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarfree_master: 538505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar spi_master_put(master); 539505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return ret; 540505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 541505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 542505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic int ti_qspi_remove(struct platform_device *pdev) 543505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar{ 544e3d8bee38543b1f3e6731916c4f11bea4d9f760fAxel Lin struct ti_qspi *qspi = platform_get_drvdata(pdev); 545cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar int ret; 546cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar 547cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar ret = pm_runtime_get_sync(qspi->dev); 548cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar if (ret < 0) { 549cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar dev_err(qspi->dev, "pm_runtime_get_sync() failed\n"); 550cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar return ret; 551cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar } 552505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 5533b3a80019ff194e86e740ec2f013a8915efd1ccfSebastian Andrzej Siewior ti_qspi_write(qspi, QSPI_WC_INT_DISABLE, QSPI_INTR_ENABLE_CLEAR_REG); 554505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 555cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar pm_runtime_put(qspi->dev); 556cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar pm_runtime_disable(&pdev->dev); 557cbcabb7a300bf5ab868c632048889a933e7cdae5Sourav Poddar 558505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar return 0; 559505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar} 560505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 561505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic const struct dev_pm_ops ti_qspi_pm_ops = { 562505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar .runtime_resume = ti_qspi_runtime_resume, 563505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar}; 564505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 565505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarstatic struct platform_driver ti_qspi_driver = { 566505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar .probe = ti_qspi_probe, 567dabefd56c6ee883bae0bdce4d5396c3f21286ab8Mark Brown .remove = ti_qspi_remove, 568505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar .driver = { 5695a33d30ff1b8fdfb5bd8f4fa46dd473bf768aeffAxel Lin .name = "ti-qspi", 570505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar .owner = THIS_MODULE, 571505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar .pm = &ti_qspi_pm_ops, 572505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar .of_match_table = ti_qspi_match, 573505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar } 574505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar}; 575505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 576505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddarmodule_platform_driver(ti_qspi_driver); 577505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav Poddar 578505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav PoddarMODULE_AUTHOR("Sourav Poddar <sourav.poddar@ti.com>"); 579505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav PoddarMODULE_LICENSE("GPL v2"); 580505a14954e2d7f2321a73f7a650bb6591d2fc1d3Sourav PoddarMODULE_DESCRIPTION("TI QSPI controller driver"); 5815a33d30ff1b8fdfb5bd8f4fa46dd473bf768aeffAxel LinMODULE_ALIAS("platform:ti-qspi"); 582