162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * SPI driver for Nvidia's Tegra20 Serial Flash Controller. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Laxman Dewangan <ldewangan@nvidia.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/completion.h> 1262306a36Sopenharmony_ci#include <linux/delay.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/io.h> 1662306a36Sopenharmony_ci#include <linux/kernel.h> 1762306a36Sopenharmony_ci#include <linux/kthread.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <linux/of_device.h> 2362306a36Sopenharmony_ci#include <linux/reset.h> 2462306a36Sopenharmony_ci#include <linux/spi/spi.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define SPI_COMMAND 0x000 2762306a36Sopenharmony_ci#define SPI_GO BIT(30) 2862306a36Sopenharmony_ci#define SPI_M_S BIT(28) 2962306a36Sopenharmony_ci#define SPI_ACTIVE_SCLK_MASK (0x3 << 26) 3062306a36Sopenharmony_ci#define SPI_ACTIVE_SCLK_DRIVE_LOW (0 << 26) 3162306a36Sopenharmony_ci#define SPI_ACTIVE_SCLK_DRIVE_HIGH (1 << 26) 3262306a36Sopenharmony_ci#define SPI_ACTIVE_SCLK_PULL_LOW (2 << 26) 3362306a36Sopenharmony_ci#define SPI_ACTIVE_SCLK_PULL_HIGH (3 << 26) 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define SPI_CK_SDA_FALLING (1 << 21) 3662306a36Sopenharmony_ci#define SPI_CK_SDA_RISING (0 << 21) 3762306a36Sopenharmony_ci#define SPI_CK_SDA_MASK (1 << 21) 3862306a36Sopenharmony_ci#define SPI_ACTIVE_SDA (0x3 << 18) 3962306a36Sopenharmony_ci#define SPI_ACTIVE_SDA_DRIVE_LOW (0 << 18) 4062306a36Sopenharmony_ci#define SPI_ACTIVE_SDA_DRIVE_HIGH (1 << 18) 4162306a36Sopenharmony_ci#define SPI_ACTIVE_SDA_PULL_LOW (2 << 18) 4262306a36Sopenharmony_ci#define SPI_ACTIVE_SDA_PULL_HIGH (3 << 18) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define SPI_CS_POL_INVERT BIT(16) 4562306a36Sopenharmony_ci#define SPI_TX_EN BIT(15) 4662306a36Sopenharmony_ci#define SPI_RX_EN BIT(14) 4762306a36Sopenharmony_ci#define SPI_CS_VAL_HIGH BIT(13) 4862306a36Sopenharmony_ci#define SPI_CS_VAL_LOW 0x0 4962306a36Sopenharmony_ci#define SPI_CS_SW BIT(12) 5062306a36Sopenharmony_ci#define SPI_CS_HW 0x0 5162306a36Sopenharmony_ci#define SPI_CS_DELAY_MASK (7 << 9) 5262306a36Sopenharmony_ci#define SPI_CS3_EN BIT(8) 5362306a36Sopenharmony_ci#define SPI_CS2_EN BIT(7) 5462306a36Sopenharmony_ci#define SPI_CS1_EN BIT(6) 5562306a36Sopenharmony_ci#define SPI_CS0_EN BIT(5) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define SPI_CS_MASK (SPI_CS3_EN | SPI_CS2_EN | \ 5862306a36Sopenharmony_ci SPI_CS1_EN | SPI_CS0_EN) 5962306a36Sopenharmony_ci#define SPI_BIT_LENGTH(x) (((x) & 0x1f) << 0) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define SPI_MODES (SPI_ACTIVE_SCLK_MASK | SPI_CK_SDA_MASK) 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#define SPI_STATUS 0x004 6462306a36Sopenharmony_ci#define SPI_BSY BIT(31) 6562306a36Sopenharmony_ci#define SPI_RDY BIT(30) 6662306a36Sopenharmony_ci#define SPI_TXF_FLUSH BIT(29) 6762306a36Sopenharmony_ci#define SPI_RXF_FLUSH BIT(28) 6862306a36Sopenharmony_ci#define SPI_RX_UNF BIT(27) 6962306a36Sopenharmony_ci#define SPI_TX_OVF BIT(26) 7062306a36Sopenharmony_ci#define SPI_RXF_EMPTY BIT(25) 7162306a36Sopenharmony_ci#define SPI_RXF_FULL BIT(24) 7262306a36Sopenharmony_ci#define SPI_TXF_EMPTY BIT(23) 7362306a36Sopenharmony_ci#define SPI_TXF_FULL BIT(22) 7462306a36Sopenharmony_ci#define SPI_BLK_CNT(count) (((count) & 0xffff) + 1) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci#define SPI_FIFO_ERROR (SPI_RX_UNF | SPI_TX_OVF) 7762306a36Sopenharmony_ci#define SPI_FIFO_EMPTY (SPI_TX_EMPTY | SPI_RX_EMPTY) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci#define SPI_RX_CMP 0x8 8062306a36Sopenharmony_ci#define SPI_DMA_CTL 0x0C 8162306a36Sopenharmony_ci#define SPI_DMA_EN BIT(31) 8262306a36Sopenharmony_ci#define SPI_IE_RXC BIT(27) 8362306a36Sopenharmony_ci#define SPI_IE_TXC BIT(26) 8462306a36Sopenharmony_ci#define SPI_PACKED BIT(20) 8562306a36Sopenharmony_ci#define SPI_RX_TRIG_MASK (0x3 << 18) 8662306a36Sopenharmony_ci#define SPI_RX_TRIG_1W (0x0 << 18) 8762306a36Sopenharmony_ci#define SPI_RX_TRIG_4W (0x1 << 18) 8862306a36Sopenharmony_ci#define SPI_TX_TRIG_MASK (0x3 << 16) 8962306a36Sopenharmony_ci#define SPI_TX_TRIG_1W (0x0 << 16) 9062306a36Sopenharmony_ci#define SPI_TX_TRIG_4W (0x1 << 16) 9162306a36Sopenharmony_ci#define SPI_DMA_BLK_COUNT(count) (((count) - 1) & 0xFFFF) 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define SPI_TX_FIFO 0x10 9462306a36Sopenharmony_ci#define SPI_RX_FIFO 0x20 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci#define DATA_DIR_TX (1 << 0) 9762306a36Sopenharmony_ci#define DATA_DIR_RX (1 << 1) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci#define MAX_CHIP_SELECT 4 10062306a36Sopenharmony_ci#define SPI_FIFO_DEPTH 4 10162306a36Sopenharmony_ci#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000)) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistruct tegra_sflash_data { 10462306a36Sopenharmony_ci struct device *dev; 10562306a36Sopenharmony_ci struct spi_master *master; 10662306a36Sopenharmony_ci spinlock_t lock; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci struct clk *clk; 10962306a36Sopenharmony_ci struct reset_control *rst; 11062306a36Sopenharmony_ci void __iomem *base; 11162306a36Sopenharmony_ci unsigned irq; 11262306a36Sopenharmony_ci u32 cur_speed; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci struct spi_device *cur_spi; 11562306a36Sopenharmony_ci unsigned cur_pos; 11662306a36Sopenharmony_ci unsigned cur_len; 11762306a36Sopenharmony_ci unsigned bytes_per_word; 11862306a36Sopenharmony_ci unsigned cur_direction; 11962306a36Sopenharmony_ci unsigned curr_xfer_words; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci unsigned cur_rx_pos; 12262306a36Sopenharmony_ci unsigned cur_tx_pos; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci u32 tx_status; 12562306a36Sopenharmony_ci u32 rx_status; 12662306a36Sopenharmony_ci u32 status_reg; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci u32 def_command_reg; 12962306a36Sopenharmony_ci u32 command_reg; 13062306a36Sopenharmony_ci u32 dma_control_reg; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci struct completion xfer_completion; 13362306a36Sopenharmony_ci struct spi_transfer *curr_xfer; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int tegra_sflash_runtime_suspend(struct device *dev); 13762306a36Sopenharmony_cistatic int tegra_sflash_runtime_resume(struct device *dev); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic inline u32 tegra_sflash_readl(struct tegra_sflash_data *tsd, 14062306a36Sopenharmony_ci unsigned long reg) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci return readl(tsd->base + reg); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistatic inline void tegra_sflash_writel(struct tegra_sflash_data *tsd, 14662306a36Sopenharmony_ci u32 val, unsigned long reg) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci writel(val, tsd->base + reg); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_cistatic void tegra_sflash_clear_status(struct tegra_sflash_data *tsd) 15262306a36Sopenharmony_ci{ 15362306a36Sopenharmony_ci /* Write 1 to clear status register */ 15462306a36Sopenharmony_ci tegra_sflash_writel(tsd, SPI_RDY | SPI_FIFO_ERROR, SPI_STATUS); 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic unsigned tegra_sflash_calculate_curr_xfer_param( 15862306a36Sopenharmony_ci struct spi_device *spi, struct tegra_sflash_data *tsd, 15962306a36Sopenharmony_ci struct spi_transfer *t) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci unsigned remain_len = t->len - tsd->cur_pos; 16262306a36Sopenharmony_ci unsigned max_word; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci tsd->bytes_per_word = DIV_ROUND_UP(t->bits_per_word, 8); 16562306a36Sopenharmony_ci max_word = remain_len / tsd->bytes_per_word; 16662306a36Sopenharmony_ci if (max_word > SPI_FIFO_DEPTH) 16762306a36Sopenharmony_ci max_word = SPI_FIFO_DEPTH; 16862306a36Sopenharmony_ci tsd->curr_xfer_words = max_word; 16962306a36Sopenharmony_ci return max_word; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic unsigned tegra_sflash_fill_tx_fifo_from_client_txbuf( 17362306a36Sopenharmony_ci struct tegra_sflash_data *tsd, struct spi_transfer *t) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci unsigned nbytes; 17662306a36Sopenharmony_ci u32 status; 17762306a36Sopenharmony_ci unsigned max_n_32bit = tsd->curr_xfer_words; 17862306a36Sopenharmony_ci u8 *tx_buf = (u8 *)t->tx_buf + tsd->cur_tx_pos; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (max_n_32bit > SPI_FIFO_DEPTH) 18162306a36Sopenharmony_ci max_n_32bit = SPI_FIFO_DEPTH; 18262306a36Sopenharmony_ci nbytes = max_n_32bit * tsd->bytes_per_word; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci status = tegra_sflash_readl(tsd, SPI_STATUS); 18562306a36Sopenharmony_ci while (!(status & SPI_TXF_FULL)) { 18662306a36Sopenharmony_ci int i; 18762306a36Sopenharmony_ci u32 x = 0; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; nbytes && (i < tsd->bytes_per_word); 19062306a36Sopenharmony_ci i++, nbytes--) 19162306a36Sopenharmony_ci x |= (u32)(*tx_buf++) << (i * 8); 19262306a36Sopenharmony_ci tegra_sflash_writel(tsd, x, SPI_TX_FIFO); 19362306a36Sopenharmony_ci if (!nbytes) 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci status = tegra_sflash_readl(tsd, SPI_STATUS); 19762306a36Sopenharmony_ci } 19862306a36Sopenharmony_ci tsd->cur_tx_pos += max_n_32bit * tsd->bytes_per_word; 19962306a36Sopenharmony_ci return max_n_32bit; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic int tegra_sflash_read_rx_fifo_to_client_rxbuf( 20362306a36Sopenharmony_ci struct tegra_sflash_data *tsd, struct spi_transfer *t) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci u32 status; 20662306a36Sopenharmony_ci unsigned int read_words = 0; 20762306a36Sopenharmony_ci u8 *rx_buf = (u8 *)t->rx_buf + tsd->cur_rx_pos; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci status = tegra_sflash_readl(tsd, SPI_STATUS); 21062306a36Sopenharmony_ci while (!(status & SPI_RXF_EMPTY)) { 21162306a36Sopenharmony_ci int i; 21262306a36Sopenharmony_ci u32 x = tegra_sflash_readl(tsd, SPI_RX_FIFO); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci for (i = 0; (i < tsd->bytes_per_word); i++) 21562306a36Sopenharmony_ci *rx_buf++ = (x >> (i*8)) & 0xFF; 21662306a36Sopenharmony_ci read_words++; 21762306a36Sopenharmony_ci status = tegra_sflash_readl(tsd, SPI_STATUS); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci tsd->cur_rx_pos += read_words * tsd->bytes_per_word; 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int tegra_sflash_start_cpu_based_transfer( 22462306a36Sopenharmony_ci struct tegra_sflash_data *tsd, struct spi_transfer *t) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci u32 val = 0; 22762306a36Sopenharmony_ci unsigned cur_words; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci if (tsd->cur_direction & DATA_DIR_TX) 23062306a36Sopenharmony_ci val |= SPI_IE_TXC; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (tsd->cur_direction & DATA_DIR_RX) 23362306a36Sopenharmony_ci val |= SPI_IE_RXC; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci tegra_sflash_writel(tsd, val, SPI_DMA_CTL); 23662306a36Sopenharmony_ci tsd->dma_control_reg = val; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (tsd->cur_direction & DATA_DIR_TX) 23962306a36Sopenharmony_ci cur_words = tegra_sflash_fill_tx_fifo_from_client_txbuf(tsd, t); 24062306a36Sopenharmony_ci else 24162306a36Sopenharmony_ci cur_words = tsd->curr_xfer_words; 24262306a36Sopenharmony_ci val |= SPI_DMA_BLK_COUNT(cur_words); 24362306a36Sopenharmony_ci tegra_sflash_writel(tsd, val, SPI_DMA_CTL); 24462306a36Sopenharmony_ci tsd->dma_control_reg = val; 24562306a36Sopenharmony_ci val |= SPI_DMA_EN; 24662306a36Sopenharmony_ci tegra_sflash_writel(tsd, val, SPI_DMA_CTL); 24762306a36Sopenharmony_ci return 0; 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic int tegra_sflash_start_transfer_one(struct spi_device *spi, 25162306a36Sopenharmony_ci struct spi_transfer *t, bool is_first_of_msg, 25262306a36Sopenharmony_ci bool is_single_xfer) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct tegra_sflash_data *tsd = spi_master_get_devdata(spi->master); 25562306a36Sopenharmony_ci u32 speed; 25662306a36Sopenharmony_ci u32 command; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci speed = t->speed_hz; 25962306a36Sopenharmony_ci if (speed != tsd->cur_speed) { 26062306a36Sopenharmony_ci clk_set_rate(tsd->clk, speed); 26162306a36Sopenharmony_ci tsd->cur_speed = speed; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci tsd->cur_spi = spi; 26562306a36Sopenharmony_ci tsd->cur_pos = 0; 26662306a36Sopenharmony_ci tsd->cur_rx_pos = 0; 26762306a36Sopenharmony_ci tsd->cur_tx_pos = 0; 26862306a36Sopenharmony_ci tsd->curr_xfer = t; 26962306a36Sopenharmony_ci tegra_sflash_calculate_curr_xfer_param(spi, tsd, t); 27062306a36Sopenharmony_ci if (is_first_of_msg) { 27162306a36Sopenharmony_ci command = tsd->def_command_reg; 27262306a36Sopenharmony_ci command |= SPI_BIT_LENGTH(t->bits_per_word - 1); 27362306a36Sopenharmony_ci command |= SPI_CS_VAL_HIGH; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci command &= ~SPI_MODES; 27662306a36Sopenharmony_ci if (spi->mode & SPI_CPHA) 27762306a36Sopenharmony_ci command |= SPI_CK_SDA_FALLING; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (spi->mode & SPI_CPOL) 28062306a36Sopenharmony_ci command |= SPI_ACTIVE_SCLK_DRIVE_HIGH; 28162306a36Sopenharmony_ci else 28262306a36Sopenharmony_ci command |= SPI_ACTIVE_SCLK_DRIVE_LOW; 28362306a36Sopenharmony_ci command |= SPI_CS0_EN << spi_get_chipselect(spi, 0); 28462306a36Sopenharmony_ci } else { 28562306a36Sopenharmony_ci command = tsd->command_reg; 28662306a36Sopenharmony_ci command &= ~SPI_BIT_LENGTH(~0); 28762306a36Sopenharmony_ci command |= SPI_BIT_LENGTH(t->bits_per_word - 1); 28862306a36Sopenharmony_ci command &= ~(SPI_RX_EN | SPI_TX_EN); 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci tsd->cur_direction = 0; 29262306a36Sopenharmony_ci if (t->rx_buf) { 29362306a36Sopenharmony_ci command |= SPI_RX_EN; 29462306a36Sopenharmony_ci tsd->cur_direction |= DATA_DIR_RX; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci if (t->tx_buf) { 29762306a36Sopenharmony_ci command |= SPI_TX_EN; 29862306a36Sopenharmony_ci tsd->cur_direction |= DATA_DIR_TX; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci tegra_sflash_writel(tsd, command, SPI_COMMAND); 30162306a36Sopenharmony_ci tsd->command_reg = command; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return tegra_sflash_start_cpu_based_transfer(tsd, t); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int tegra_sflash_transfer_one_message(struct spi_master *master, 30762306a36Sopenharmony_ci struct spi_message *msg) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci bool is_first_msg = true; 31062306a36Sopenharmony_ci int single_xfer; 31162306a36Sopenharmony_ci struct tegra_sflash_data *tsd = spi_master_get_devdata(master); 31262306a36Sopenharmony_ci struct spi_transfer *xfer; 31362306a36Sopenharmony_ci struct spi_device *spi = msg->spi; 31462306a36Sopenharmony_ci int ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci msg->status = 0; 31762306a36Sopenharmony_ci msg->actual_length = 0; 31862306a36Sopenharmony_ci single_xfer = list_is_singular(&msg->transfers); 31962306a36Sopenharmony_ci list_for_each_entry(xfer, &msg->transfers, transfer_list) { 32062306a36Sopenharmony_ci reinit_completion(&tsd->xfer_completion); 32162306a36Sopenharmony_ci ret = tegra_sflash_start_transfer_one(spi, xfer, 32262306a36Sopenharmony_ci is_first_msg, single_xfer); 32362306a36Sopenharmony_ci if (ret < 0) { 32462306a36Sopenharmony_ci dev_err(tsd->dev, 32562306a36Sopenharmony_ci "spi can not start transfer, err %d\n", ret); 32662306a36Sopenharmony_ci goto exit; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci is_first_msg = false; 32962306a36Sopenharmony_ci ret = wait_for_completion_timeout(&tsd->xfer_completion, 33062306a36Sopenharmony_ci SPI_DMA_TIMEOUT); 33162306a36Sopenharmony_ci if (WARN_ON(ret == 0)) { 33262306a36Sopenharmony_ci dev_err(tsd->dev, 33362306a36Sopenharmony_ci "spi transfer timeout, err %d\n", ret); 33462306a36Sopenharmony_ci ret = -EIO; 33562306a36Sopenharmony_ci goto exit; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (tsd->tx_status || tsd->rx_status) { 33962306a36Sopenharmony_ci dev_err(tsd->dev, "Error in Transfer\n"); 34062306a36Sopenharmony_ci ret = -EIO; 34162306a36Sopenharmony_ci goto exit; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci msg->actual_length += xfer->len; 34462306a36Sopenharmony_ci if (xfer->cs_change && xfer->delay.value) { 34562306a36Sopenharmony_ci tegra_sflash_writel(tsd, tsd->def_command_reg, 34662306a36Sopenharmony_ci SPI_COMMAND); 34762306a36Sopenharmony_ci spi_transfer_delay_exec(xfer); 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci } 35062306a36Sopenharmony_ci ret = 0; 35162306a36Sopenharmony_ciexit: 35262306a36Sopenharmony_ci tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND); 35362306a36Sopenharmony_ci msg->status = ret; 35462306a36Sopenharmony_ci spi_finalize_current_message(master); 35562306a36Sopenharmony_ci return ret; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic irqreturn_t handle_cpu_based_xfer(struct tegra_sflash_data *tsd) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct spi_transfer *t = tsd->curr_xfer; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci spin_lock(&tsd->lock); 36362306a36Sopenharmony_ci if (tsd->tx_status || tsd->rx_status || (tsd->status_reg & SPI_BSY)) { 36462306a36Sopenharmony_ci dev_err(tsd->dev, 36562306a36Sopenharmony_ci "CpuXfer ERROR bit set 0x%x\n", tsd->status_reg); 36662306a36Sopenharmony_ci dev_err(tsd->dev, 36762306a36Sopenharmony_ci "CpuXfer 0x%08x:0x%08x\n", tsd->command_reg, 36862306a36Sopenharmony_ci tsd->dma_control_reg); 36962306a36Sopenharmony_ci reset_control_assert(tsd->rst); 37062306a36Sopenharmony_ci udelay(2); 37162306a36Sopenharmony_ci reset_control_deassert(tsd->rst); 37262306a36Sopenharmony_ci complete(&tsd->xfer_completion); 37362306a36Sopenharmony_ci goto exit; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (tsd->cur_direction & DATA_DIR_RX) 37762306a36Sopenharmony_ci tegra_sflash_read_rx_fifo_to_client_rxbuf(tsd, t); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (tsd->cur_direction & DATA_DIR_TX) 38062306a36Sopenharmony_ci tsd->cur_pos = tsd->cur_tx_pos; 38162306a36Sopenharmony_ci else 38262306a36Sopenharmony_ci tsd->cur_pos = tsd->cur_rx_pos; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (tsd->cur_pos == t->len) { 38562306a36Sopenharmony_ci complete(&tsd->xfer_completion); 38662306a36Sopenharmony_ci goto exit; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci tegra_sflash_calculate_curr_xfer_param(tsd->cur_spi, tsd, t); 39062306a36Sopenharmony_ci tegra_sflash_start_cpu_based_transfer(tsd, t); 39162306a36Sopenharmony_ciexit: 39262306a36Sopenharmony_ci spin_unlock(&tsd->lock); 39362306a36Sopenharmony_ci return IRQ_HANDLED; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_cistatic irqreturn_t tegra_sflash_isr(int irq, void *context_data) 39762306a36Sopenharmony_ci{ 39862306a36Sopenharmony_ci struct tegra_sflash_data *tsd = context_data; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci tsd->status_reg = tegra_sflash_readl(tsd, SPI_STATUS); 40162306a36Sopenharmony_ci if (tsd->cur_direction & DATA_DIR_TX) 40262306a36Sopenharmony_ci tsd->tx_status = tsd->status_reg & SPI_TX_OVF; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if (tsd->cur_direction & DATA_DIR_RX) 40562306a36Sopenharmony_ci tsd->rx_status = tsd->status_reg & SPI_RX_UNF; 40662306a36Sopenharmony_ci tegra_sflash_clear_status(tsd); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return handle_cpu_based_xfer(tsd); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic const struct of_device_id tegra_sflash_of_match[] = { 41262306a36Sopenharmony_ci { .compatible = "nvidia,tegra20-sflash", }, 41362306a36Sopenharmony_ci {} 41462306a36Sopenharmony_ci}; 41562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_sflash_of_match); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_cistatic int tegra_sflash_probe(struct platform_device *pdev) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct spi_master *master; 42062306a36Sopenharmony_ci struct tegra_sflash_data *tsd; 42162306a36Sopenharmony_ci int ret; 42262306a36Sopenharmony_ci const struct of_device_id *match; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci match = of_match_device(tegra_sflash_of_match, &pdev->dev); 42562306a36Sopenharmony_ci if (!match) { 42662306a36Sopenharmony_ci dev_err(&pdev->dev, "Error: No device match found\n"); 42762306a36Sopenharmony_ci return -ENODEV; 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(*tsd)); 43162306a36Sopenharmony_ci if (!master) { 43262306a36Sopenharmony_ci dev_err(&pdev->dev, "master allocation failed\n"); 43362306a36Sopenharmony_ci return -ENOMEM; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* the spi->mode bits understood by this driver: */ 43762306a36Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA; 43862306a36Sopenharmony_ci master->transfer_one_message = tegra_sflash_transfer_one_message; 43962306a36Sopenharmony_ci master->auto_runtime_pm = true; 44062306a36Sopenharmony_ci master->num_chipselect = MAX_CHIP_SELECT; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci platform_set_drvdata(pdev, master); 44362306a36Sopenharmony_ci tsd = spi_master_get_devdata(master); 44462306a36Sopenharmony_ci tsd->master = master; 44562306a36Sopenharmony_ci tsd->dev = &pdev->dev; 44662306a36Sopenharmony_ci spin_lock_init(&tsd->lock); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (of_property_read_u32(tsd->dev->of_node, "spi-max-frequency", 44962306a36Sopenharmony_ci &master->max_speed_hz)) 45062306a36Sopenharmony_ci master->max_speed_hz = 25000000; /* 25MHz */ 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci tsd->base = devm_platform_ioremap_resource(pdev, 0); 45362306a36Sopenharmony_ci if (IS_ERR(tsd->base)) { 45462306a36Sopenharmony_ci ret = PTR_ERR(tsd->base); 45562306a36Sopenharmony_ci goto exit_free_master; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci ret = platform_get_irq(pdev, 0); 45962306a36Sopenharmony_ci if (ret < 0) 46062306a36Sopenharmony_ci goto exit_free_master; 46162306a36Sopenharmony_ci tsd->irq = ret; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci ret = request_irq(tsd->irq, tegra_sflash_isr, 0, 46462306a36Sopenharmony_ci dev_name(&pdev->dev), tsd); 46562306a36Sopenharmony_ci if (ret < 0) { 46662306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", 46762306a36Sopenharmony_ci tsd->irq); 46862306a36Sopenharmony_ci goto exit_free_master; 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci tsd->clk = devm_clk_get(&pdev->dev, NULL); 47262306a36Sopenharmony_ci if (IS_ERR(tsd->clk)) { 47362306a36Sopenharmony_ci dev_err(&pdev->dev, "can not get clock\n"); 47462306a36Sopenharmony_ci ret = PTR_ERR(tsd->clk); 47562306a36Sopenharmony_ci goto exit_free_irq; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci tsd->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); 47962306a36Sopenharmony_ci if (IS_ERR(tsd->rst)) { 48062306a36Sopenharmony_ci dev_err(&pdev->dev, "can not get reset\n"); 48162306a36Sopenharmony_ci ret = PTR_ERR(tsd->rst); 48262306a36Sopenharmony_ci goto exit_free_irq; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci init_completion(&tsd->xfer_completion); 48662306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 48762306a36Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) { 48862306a36Sopenharmony_ci ret = tegra_sflash_runtime_resume(&pdev->dev); 48962306a36Sopenharmony_ci if (ret) 49062306a36Sopenharmony_ci goto exit_pm_disable; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(&pdev->dev); 49462306a36Sopenharmony_ci if (ret < 0) { 49562306a36Sopenharmony_ci dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); 49662306a36Sopenharmony_ci goto exit_pm_disable; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* Reset controller */ 50062306a36Sopenharmony_ci reset_control_assert(tsd->rst); 50162306a36Sopenharmony_ci udelay(2); 50262306a36Sopenharmony_ci reset_control_deassert(tsd->rst); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci tsd->def_command_reg = SPI_M_S | SPI_CS_SW; 50562306a36Sopenharmony_ci tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND); 50662306a36Sopenharmony_ci pm_runtime_put(&pdev->dev); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 50962306a36Sopenharmony_ci ret = devm_spi_register_master(&pdev->dev, master); 51062306a36Sopenharmony_ci if (ret < 0) { 51162306a36Sopenharmony_ci dev_err(&pdev->dev, "can not register to master err %d\n", ret); 51262306a36Sopenharmony_ci goto exit_pm_disable; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci return ret; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ciexit_pm_disable: 51762306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 51862306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 51962306a36Sopenharmony_ci tegra_sflash_runtime_suspend(&pdev->dev); 52062306a36Sopenharmony_ciexit_free_irq: 52162306a36Sopenharmony_ci free_irq(tsd->irq, tsd); 52262306a36Sopenharmony_ciexit_free_master: 52362306a36Sopenharmony_ci spi_master_put(master); 52462306a36Sopenharmony_ci return ret; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_cistatic void tegra_sflash_remove(struct platform_device *pdev) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci struct spi_master *master = platform_get_drvdata(pdev); 53062306a36Sopenharmony_ci struct tegra_sflash_data *tsd = spi_master_get_devdata(master); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci free_irq(tsd->irq, tsd); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 53562306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 53662306a36Sopenharmony_ci tegra_sflash_runtime_suspend(&pdev->dev); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 54062306a36Sopenharmony_cistatic int tegra_sflash_suspend(struct device *dev) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci return spi_master_suspend(master); 54562306a36Sopenharmony_ci} 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int tegra_sflash_resume(struct device *dev) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 55062306a36Sopenharmony_ci struct tegra_sflash_data *tsd = spi_master_get_devdata(master); 55162306a36Sopenharmony_ci int ret; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 55462306a36Sopenharmony_ci if (ret < 0) { 55562306a36Sopenharmony_ci dev_err(dev, "pm runtime failed, e = %d\n", ret); 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci tegra_sflash_writel(tsd, tsd->command_reg, SPI_COMMAND); 55962306a36Sopenharmony_ci pm_runtime_put(dev); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return spi_master_resume(master); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci#endif 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic int tegra_sflash_runtime_suspend(struct device *dev) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 56862306a36Sopenharmony_ci struct tegra_sflash_data *tsd = spi_master_get_devdata(master); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* Flush all write which are in PPSB queue by reading back */ 57162306a36Sopenharmony_ci tegra_sflash_readl(tsd, SPI_COMMAND); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci clk_disable_unprepare(tsd->clk); 57462306a36Sopenharmony_ci return 0; 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int tegra_sflash_runtime_resume(struct device *dev) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 58062306a36Sopenharmony_ci struct tegra_sflash_data *tsd = spi_master_get_devdata(master); 58162306a36Sopenharmony_ci int ret; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci ret = clk_prepare_enable(tsd->clk); 58462306a36Sopenharmony_ci if (ret < 0) { 58562306a36Sopenharmony_ci dev_err(tsd->dev, "clk_prepare failed: %d\n", ret); 58662306a36Sopenharmony_ci return ret; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic const struct dev_pm_ops slink_pm_ops = { 59262306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(tegra_sflash_runtime_suspend, 59362306a36Sopenharmony_ci tegra_sflash_runtime_resume, NULL) 59462306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(tegra_sflash_suspend, tegra_sflash_resume) 59562306a36Sopenharmony_ci}; 59662306a36Sopenharmony_cistatic struct platform_driver tegra_sflash_driver = { 59762306a36Sopenharmony_ci .driver = { 59862306a36Sopenharmony_ci .name = "spi-tegra-sflash", 59962306a36Sopenharmony_ci .pm = &slink_pm_ops, 60062306a36Sopenharmony_ci .of_match_table = tegra_sflash_of_match, 60162306a36Sopenharmony_ci }, 60262306a36Sopenharmony_ci .probe = tegra_sflash_probe, 60362306a36Sopenharmony_ci .remove_new = tegra_sflash_remove, 60462306a36Sopenharmony_ci}; 60562306a36Sopenharmony_cimodule_platform_driver(tegra_sflash_driver); 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ciMODULE_ALIAS("platform:spi-tegra-sflash"); 60862306a36Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra20 Serial Flash Controller Driver"); 60962306a36Sopenharmony_ciMODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); 61062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 611