1e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang/* 2ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely * Designware SPI core controller driver (refer pxa2xx_spi.c) 3e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * 4e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * Copyright (c) 2009, Intel Corporation. 5e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * 6e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * This program is free software; you can redistribute it and/or modify it 7e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * under the terms and conditions of the GNU General Public License, 8e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * version 2, as published by the Free Software Foundation. 9e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * 10e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * This program is distributed in the hope it will be useful, but WITHOUT 11e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * more details. 14e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang */ 15e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 16e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#include <linux/dma-mapping.h> 17e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#include <linux/interrupt.h> 18d7614de422c0b55db0c1013a6c72330187536004Paul Gortmaker#include <linux/module.h> 19e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#include <linux/highmem.h> 20e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#include <linux/delay.h> 215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 22e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#include <linux/spi/spi.h> 23d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach#include <linux/gpio.h> 24e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 25ca632f556697d45d67ed5cada7cedf3ddfe0db4bGrant Likely#include "spi-dw.h" 26568a60eda2e90a11bb3d7f8ef3f6800e9b60d4e5Grant Likely 27e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#ifdef CONFIG_DEBUG_FS 28e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#include <linux/debugfs.h> 29e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#endif 30e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 31e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#define START_STATE ((void *)0) 32e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#define RUNNING_STATE ((void *)1) 33e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#define DONE_STATE ((void *)2) 34e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#define ERROR_STATE ((void *)-1) 35e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 36e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang/* Slave spi_dev related */ 37e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstruct chip_data { 38e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u16 cr0; 39e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 cs; /* chip select pin */ 40e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 n_bytes; /* current is a 1/2/4 byte op */ 41e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 tmode; /* TR/TO/RO/EEPROM */ 42e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 type; /* SPI/SSP/MicroWire */ 43e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 44e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 poll_mode; /* 1 means use poll mode */ 45e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 46e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u32 dma_width; 47e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u32 rx_threshold; 48e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u32 tx_threshold; 49e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 enable_dma; 50e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 bits_per_word; 51e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u16 clk_div; /* baud rate divider */ 52e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u32 speed_hz; /* baud rate */ 53e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang void (*cs_control)(u32 command); 54e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang}; 55e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 56e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#ifdef CONFIG_DEBUG_FS 57e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#define SPI_REGS_BUFSIZE 1024 5853288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenkostatic ssize_t dw_spi_show_regs(struct file *file, char __user *user_buf, 5953288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko size_t count, loff_t *ppos) 60e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 6153288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko struct dw_spi *dws = file->private_data; 62e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang char *buf; 63e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u32 len = 0; 64e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang ssize_t ret; 65e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 66e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang buf = kzalloc(SPI_REGS_BUFSIZE, GFP_KERNEL); 67e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (!buf) 68e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return 0; 69e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 70e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 7153288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko "%s registers:\n", dev_name(&dws->master->dev)); 72e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 73e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang "=================================\n"); 74e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 757eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "CTRL0: \t\t0x%08x\n", dw_readl(dws, DW_SPI_CTRL0)); 76e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 777eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "CTRL1: \t\t0x%08x\n", dw_readl(dws, DW_SPI_CTRL1)); 78e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 797eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "SSIENR: \t0x%08x\n", dw_readl(dws, DW_SPI_SSIENR)); 80e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 817eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "SER: \t\t0x%08x\n", dw_readl(dws, DW_SPI_SER)); 82e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 837eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "BAUDR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_BAUDR)); 84e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 857eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "TXFTLR: \t0x%08x\n", dw_readl(dws, DW_SPI_TXFLTR)); 86e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 877eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "RXFTLR: \t0x%08x\n", dw_readl(dws, DW_SPI_RXFLTR)); 88e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 897eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "TXFLR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_TXFLR)); 90e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 917eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "RXFLR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_RXFLR)); 92e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 937eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "SR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_SR)); 94e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 957eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "IMR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_IMR)); 96e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 977eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "ISR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_ISR)); 98e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 997eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "DMACR: \t\t0x%08x\n", dw_readl(dws, DW_SPI_DMACR)); 100e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 1017eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "DMATDLR: \t0x%08x\n", dw_readl(dws, DW_SPI_DMATDLR)); 102e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 1037eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten "DMARDLR: \t0x%08x\n", dw_readl(dws, DW_SPI_DMARDLR)); 104e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang len += snprintf(buf + len, SPI_REGS_BUFSIZE - len, 105e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang "=================================\n"); 106e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 10753288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); 108e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang kfree(buf); 109e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return ret; 110e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 111e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 11253288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenkostatic const struct file_operations dw_spi_regs_ops = { 113e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang .owner = THIS_MODULE, 114234e340582901211f40d8c732afc49f0630ecf05Stephen Boyd .open = simple_open, 11553288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko .read = dw_spi_show_regs, 1166038f373a3dc1f1c26496e60b6c40b164716f07eArnd Bergmann .llseek = default_llseek, 117e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang}; 118e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 11953288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenkostatic int dw_spi_debugfs_init(struct dw_spi *dws) 120e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 12153288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko dws->debugfs = debugfs_create_dir("dw_spi", NULL); 122e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (!dws->debugfs) 123e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return -ENOMEM; 124e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 125e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang debugfs_create_file("registers", S_IFREG | S_IRUGO, 12653288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko dws->debugfs, (void *)dws, &dw_spi_regs_ops); 127e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return 0; 128e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 129e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 13053288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenkostatic void dw_spi_debugfs_remove(struct dw_spi *dws) 131e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 132fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han debugfs_remove_recursive(dws->debugfs); 133e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 134e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 135e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#else 13653288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenkostatic inline int dw_spi_debugfs_init(struct dw_spi *dws) 137e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 13820a588fcc862df79d8fcafbc41950e3ae93dea09George Shore return 0; 139e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 140e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 14153288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenkostatic inline void dw_spi_debugfs_remove(struct dw_spi *dws) 142e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 143e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 144e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang#endif /* CONFIG_DEBUG_FS */ 145e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 1462ff271bf6505038d8c937e73438ea3c80c387439Alek Du/* Return the max entries we can fill into tx fifo */ 1472ff271bf6505038d8c937e73438ea3c80c387439Alek Dustatic inline u32 tx_max(struct dw_spi *dws) 1482ff271bf6505038d8c937e73438ea3c80c387439Alek Du{ 1492ff271bf6505038d8c937e73438ea3c80c387439Alek Du u32 tx_left, tx_room, rxtx_gap; 1502ff271bf6505038d8c937e73438ea3c80c387439Alek Du 1512ff271bf6505038d8c937e73438ea3c80c387439Alek Du tx_left = (dws->tx_end - dws->tx) / dws->n_bytes; 1527eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten tx_room = dws->fifo_len - dw_readw(dws, DW_SPI_TXFLR); 1532ff271bf6505038d8c937e73438ea3c80c387439Alek Du 1542ff271bf6505038d8c937e73438ea3c80c387439Alek Du /* 1552ff271bf6505038d8c937e73438ea3c80c387439Alek Du * Another concern is about the tx/rx mismatch, we 1562ff271bf6505038d8c937e73438ea3c80c387439Alek Du * though to use (dws->fifo_len - rxflr - txflr) as 1572ff271bf6505038d8c937e73438ea3c80c387439Alek Du * one maximum value for tx, but it doesn't cover the 1582ff271bf6505038d8c937e73438ea3c80c387439Alek Du * data which is out of tx/rx fifo and inside the 1592ff271bf6505038d8c937e73438ea3c80c387439Alek Du * shift registers. So a control from sw point of 1602ff271bf6505038d8c937e73438ea3c80c387439Alek Du * view is taken. 1612ff271bf6505038d8c937e73438ea3c80c387439Alek Du */ 1622ff271bf6505038d8c937e73438ea3c80c387439Alek Du rxtx_gap = ((dws->rx_end - dws->rx) - (dws->tx_end - dws->tx)) 1632ff271bf6505038d8c937e73438ea3c80c387439Alek Du / dws->n_bytes; 1642ff271bf6505038d8c937e73438ea3c80c387439Alek Du 1652ff271bf6505038d8c937e73438ea3c80c387439Alek Du return min3(tx_left, tx_room, (u32) (dws->fifo_len - rxtx_gap)); 1662ff271bf6505038d8c937e73438ea3c80c387439Alek Du} 1672ff271bf6505038d8c937e73438ea3c80c387439Alek Du 1682ff271bf6505038d8c937e73438ea3c80c387439Alek Du/* Return the max entries we should read out of rx fifo */ 1692ff271bf6505038d8c937e73438ea3c80c387439Alek Dustatic inline u32 rx_max(struct dw_spi *dws) 1702ff271bf6505038d8c937e73438ea3c80c387439Alek Du{ 1712ff271bf6505038d8c937e73438ea3c80c387439Alek Du u32 rx_left = (dws->rx_end - dws->rx) / dws->n_bytes; 1722ff271bf6505038d8c937e73438ea3c80c387439Alek Du 173fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han return min_t(u32, rx_left, dw_readw(dws, DW_SPI_RXFLR)); 1742ff271bf6505038d8c937e73438ea3c80c387439Alek Du} 1752ff271bf6505038d8c937e73438ea3c80c387439Alek Du 1763b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Dustatic void dw_writer(struct dw_spi *dws) 177e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 1782ff271bf6505038d8c937e73438ea3c80c387439Alek Du u32 max = tx_max(dws); 179de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang u16 txw = 0; 180e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 1812ff271bf6505038d8c937e73438ea3c80c387439Alek Du while (max--) { 1822ff271bf6505038d8c937e73438ea3c80c387439Alek Du /* Set the tx word if the transfer's original "tx" is not null */ 1832ff271bf6505038d8c937e73438ea3c80c387439Alek Du if (dws->tx_end - dws->len) { 1842ff271bf6505038d8c937e73438ea3c80c387439Alek Du if (dws->n_bytes == 1) 1852ff271bf6505038d8c937e73438ea3c80c387439Alek Du txw = *(u8 *)(dws->tx); 1862ff271bf6505038d8c937e73438ea3c80c387439Alek Du else 1872ff271bf6505038d8c937e73438ea3c80c387439Alek Du txw = *(u16 *)(dws->tx); 1882ff271bf6505038d8c937e73438ea3c80c387439Alek Du } 1897eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_writew(dws, DW_SPI_DR, txw); 1902ff271bf6505038d8c937e73438ea3c80c387439Alek Du dws->tx += dws->n_bytes; 191e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 192e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 193e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 1943b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Dustatic void dw_reader(struct dw_spi *dws) 195e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 1962ff271bf6505038d8c937e73438ea3c80c387439Alek Du u32 max = rx_max(dws); 197de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang u16 rxw; 198e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 1992ff271bf6505038d8c937e73438ea3c80c387439Alek Du while (max--) { 2007eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten rxw = dw_readw(dws, DW_SPI_DR); 201de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang /* Care rx only if the transfer's original "rx" is not null */ 202de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang if (dws->rx_end - dws->len) { 203de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang if (dws->n_bytes == 1) 204de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang *(u8 *)(dws->rx) = rxw; 205de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang else 206de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang *(u16 *)(dws->rx) = rxw; 207de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang } 208de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang dws->rx += dws->n_bytes; 209e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 210e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 211e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 212e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic void *next_transfer(struct dw_spi *dws) 213e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 214e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_message *msg = dws->cur_msg; 215e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_transfer *trans = dws->cur_transfer; 216e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 217e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Move to next transfer */ 218e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (trans->transfer_list.next != &msg->transfers) { 219e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_transfer = 220e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang list_entry(trans->transfer_list.next, 221e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_transfer, 222e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang transfer_list); 223e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return RUNNING_STATE; 224fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han } 225fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han 226fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han return DONE_STATE; 227e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 228e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 229e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang/* 230e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * Note: first step is the protocol driver prepares 231e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * a dma-capable memory, and this func just need translate 232e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * the virt addr to physical 233e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang */ 234e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic int map_dma_buffers(struct dw_spi *dws) 235e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 2367063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang if (!dws->cur_msg->is_dma_mapped 2377063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang || !dws->dma_inited 2387063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang || !dws->cur_chip->enable_dma 2397063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang || !dws->dma_ops) 240e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return 0; 241e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 242e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (dws->cur_transfer->tx_dma) 243e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->tx_dma = dws->cur_transfer->tx_dma; 244e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 245e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (dws->cur_transfer->rx_dma) 246e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->rx_dma = dws->cur_transfer->rx_dma; 247e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 248e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return 1; 249e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 250e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 251e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang/* Caller already set message->status; dma and pio irqs are blocked */ 252e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic void giveback(struct dw_spi *dws) 253e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 254e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_transfer *last_transfer; 255e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_message *msg; 256e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 257e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang msg = dws->cur_msg; 258e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_msg = NULL; 259e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_transfer = NULL; 260e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->prev_chip = dws->cur_chip; 261e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_chip = NULL; 262e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->dma_mapped = 0; 263e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 26423e2c2aa45a213ea25636ac5add66c2507e7361bAxel Lin last_transfer = list_last_entry(&msg->transfers, struct spi_transfer, 265e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang transfer_list); 266e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 267d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach if (!last_transfer->cs_change) 26808a707b87874eaaa0f336ab604ecd6e5e9f286ddAndy Shevchenko spi_chip_sel(dws, msg->spi, 0); 269e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 270ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach spi_finalize_current_message(dws->master); 271e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 272e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 273e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic void int_error_stop(struct dw_spi *dws, const char *msg) 274e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 2758a33a373e5ffb6040c58ff41ea48ba21d5f8b5e9Alek Du /* Stop the hw */ 276e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 0); 277e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 278e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dev_err(&dws->master->dev, "%s\n", msg); 279e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_msg->state = ERROR_STATE; 280e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang tasklet_schedule(&dws->pump_transfers); 281e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 282e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 2837063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tangvoid dw_spi_xfer_done(struct dw_spi *dws) 284e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 28525985edcedea6396277003854657b5f3cb31a628Lucas De Marchi /* Update total byte transferred return count actual bytes read */ 286e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_msg->actual_length += dws->len; 287e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 288e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Move to next transfer */ 289e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_msg->state = next_transfer(dws); 290e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 291e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Handle end of message */ 292e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (dws->cur_msg->state == DONE_STATE) { 293e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_msg->status = 0; 294e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang giveback(dws); 295e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } else 296e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang tasklet_schedule(&dws->pump_transfers); 297e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 2987063c0d942a1af2993531fbe52b4c74c1db818c4Feng TangEXPORT_SYMBOL_GPL(dw_spi_xfer_done); 299e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 300e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic irqreturn_t interrupt_transfer(struct dw_spi *dws) 301e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 3027eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten u16 irq_status = dw_readw(dws, DW_SPI_ISR); 303e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 304e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Error handling */ 305e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (irq_status & (SPI_INT_TXOI | SPI_INT_RXOI | SPI_INT_RXUI)) { 3067eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_readw(dws, DW_SPI_TXOICR); 3077eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_readw(dws, DW_SPI_RXOICR); 3087eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_readw(dws, DW_SPI_RXUICR); 3093b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du int_error_stop(dws, "interrupt_transfer: fifo overrun/underrun"); 310e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return IRQ_HANDLED; 311e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 312e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 3133b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du dw_reader(dws); 3143b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du if (dws->rx_end == dws->rx) { 3153b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du spi_mask_intr(dws, SPI_INT_TXEI); 3163b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du dw_spi_xfer_done(dws); 3173b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du return IRQ_HANDLED; 3183b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du } 319552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang if (irq_status & SPI_INT_TXEI) { 320552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang spi_mask_intr(dws, SPI_INT_TXEI); 3213b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du dw_writer(dws); 3223b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du /* Enable TX irq always, it will be disabled when RX finished */ 3233b8a4dd3ebfcc647260ad5c39ef4f73eb3a6b155Alek Du spi_umask_intr(dws, SPI_INT_TXEI); 324e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 325e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 326e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return IRQ_HANDLED; 327e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 328e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 329e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic irqreturn_t dw_spi_irq(int irq, void *dev_id) 330e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 331e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct dw_spi *dws = dev_id; 3327eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten u16 irq_status = dw_readw(dws, DW_SPI_ISR) & 0x3f; 333cbcc062abb16d39839b3d8d4e3d20360fc21eb58Yong Wang 334cbcc062abb16d39839b3d8d4e3d20360fc21eb58Yong Wang if (!irq_status) 335cbcc062abb16d39839b3d8d4e3d20360fc21eb58Yong Wang return IRQ_NONE; 336e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 337e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (!dws->cur_msg) { 338e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_mask_intr(dws, SPI_INT_TXEI); 339e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return IRQ_HANDLED; 340e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 341e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 342e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return dws->transfer_handler(dws); 343e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 344e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 345e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang/* Must be called inside pump_transfers() */ 346e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic void poll_transfer(struct dw_spi *dws) 347e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 3482ff271bf6505038d8c937e73438ea3c80c387439Alek Du do { 3492ff271bf6505038d8c937e73438ea3c80c387439Alek Du dw_writer(dws); 350de6efe0a966cf86b3c4039a610b2d4157db707f2Feng Tang dw_reader(dws); 3512ff271bf6505038d8c937e73438ea3c80c387439Alek Du cpu_relax(); 3522ff271bf6505038d8c937e73438ea3c80c387439Alek Du } while (dws->rx_end > dws->rx); 353e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 3547063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang dw_spi_xfer_done(dws); 355e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 356e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 357e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic void pump_transfers(unsigned long data) 358e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 359e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct dw_spi *dws = (struct dw_spi *)data; 360e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_message *message = NULL; 361e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_transfer *transfer = NULL; 362e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_transfer *previous = NULL; 363e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_device *spi = NULL; 364e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct chip_data *chip = NULL; 365e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 bits = 0; 366e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 imask = 0; 367e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u8 cs_change = 0; 368552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang u16 txint_level = 0; 369e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u16 clk_div = 0; 370e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u32 speed = 0; 371e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang u32 cr0 = 0; 372e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 373e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Get current state information */ 374e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang message = dws->cur_msg; 375e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang transfer = dws->cur_transfer; 376e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip = dws->cur_chip; 377e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi = message->spi; 378e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 379e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (message->state == ERROR_STATE) { 380e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang message->status = -EIO; 381e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang goto early_exit; 382e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 383e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 384e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Handle end of message */ 385e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (message->state == DONE_STATE) { 386e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang message->status = 0; 387e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang goto early_exit; 388e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 389e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 390c3c6e231d860774037e7001ff3d536e5644fe2daAndy Shevchenko /* Delay if requested at end of transfer */ 391e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (message->state == RUNNING_STATE) { 392e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang previous = list_entry(transfer->transfer_list.prev, 393e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_transfer, 394e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang transfer_list); 395e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (previous->delay_usecs) 396e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang udelay(previous->delay_usecs); 397e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 398e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 399e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->n_bytes = chip->n_bytes; 400e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->dma_width = chip->dma_width; 401e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cs_control = chip->cs_control; 402e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 403e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->rx_dma = transfer->rx_dma; 404e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->tx_dma = transfer->tx_dma; 405e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->tx = (void *)transfer->tx_buf; 406e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->tx_end = dws->tx + transfer->len; 407e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->rx = transfer->rx_buf; 408e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->rx_end = dws->rx + transfer->len; 409e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->len = dws->cur_transfer->len; 410e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (chip != dws->prev_chip) 411e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang cs_change = 1; 412e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 413e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang cr0 = chip->cr0; 414e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 415e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Handle per transfer options for bpw and speed */ 416e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (transfer->speed_hz) { 417e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang speed = chip->speed_hz; 418e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 4190a8727e69778683495058852f783eeda141a754eThor Thayer if ((transfer->speed_hz != speed) || (!chip->clk_div)) { 420e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang speed = transfer->speed_hz; 421e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 422e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* clk_div doesn't support odd number */ 423e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang clk_div = dws->max_freq / speed; 424552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang clk_div = (clk_div + 1) & 0xfffe; 425e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 426e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->speed_hz = speed; 427e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->clk_div = clk_div; 428e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 429e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 430e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (transfer->bits_per_word) { 431e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang bits = transfer->bits_per_word; 43224778be20f87d5aadb19624fc768b3159fa43efcStephen Warren dws->n_bytes = dws->dma_width = bits >> 3; 433e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang cr0 = (bits - 1) 434e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang | (chip->type << SPI_FRF_OFFSET) 435e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang | (spi->mode << SPI_MODE_OFFSET) 436e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang | (chip->tmode << SPI_TMOD_OFFSET); 437e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 438e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang message->state = RUNNING_STATE; 439e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 440052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore /* 441052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore * Adjust transfer mode if necessary. Requires platform dependent 442052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore * chipselect mechanism. 443052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore */ 444052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore if (dws->cs_control) { 445052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore if (dws->rx && dws->tx) 446e3e55ff5854655d8723ad8b307f02515aecc3df5Feng Tang chip->tmode = SPI_TMOD_TR; 447052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore else if (dws->rx) 448e3e55ff5854655d8723ad8b307f02515aecc3df5Feng Tang chip->tmode = SPI_TMOD_RO; 449052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore else 450e3e55ff5854655d8723ad8b307f02515aecc3df5Feng Tang chip->tmode = SPI_TMOD_TO; 451052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore 452e3e55ff5854655d8723ad8b307f02515aecc3df5Feng Tang cr0 &= ~SPI_TMOD_MASK; 453052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore cr0 |= (chip->tmode << SPI_TMOD_OFFSET); 454052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore } 455052dc7c45d8f685fb3720a08331ba3e91e87937eGeorge Shore 456e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Check if current transfer is a DMA transaction */ 457e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->dma_mapped = map_dma_buffers(dws); 458e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 459552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang /* 460552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang * Interrupt mode 461552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang * we only need set the TXEI IRQ, as TX/RX always happen syncronizely 462552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang */ 463e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (!dws->dma_mapped && !chip->poll_mode) { 464552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang int templen = dws->len / dws->n_bytes; 465fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han 466552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang txint_level = dws->fifo_len / 2; 467552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang txint_level = (templen > txint_level) ? txint_level : templen; 468552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang 469fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han imask |= SPI_INT_TXEI | SPI_INT_TXOI | 470fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han SPI_INT_RXUI | SPI_INT_RXOI; 471e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->transfer_handler = interrupt_transfer; 472e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 473e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 474e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* 475e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * Reprogram registers only if 476e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * 1. chip select changes 477e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * 2. clk_div is changed 478e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * 3. control value changes 479e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang */ 4807eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten if (dw_readw(dws, DW_SPI_CTRL0) != cr0 || cs_change || clk_div || imask) { 481e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 0); 482e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 4837eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten if (dw_readw(dws, DW_SPI_CTRL0) != cr0) 4847eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_writew(dws, DW_SPI_CTRL0, cr0); 485e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 486552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang spi_set_clk(dws, clk_div ? clk_div : chip->clk_div); 487d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach spi_chip_sel(dws, spi, 1); 488552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang 4892f263d9d4f0432e4f7a708c95fab82f83ec14947Justin P. Mattock /* Set the interrupt mask, for poll mode just disable all int */ 490e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_mask_intr(dws, 0xff); 491552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang if (imask) 492e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_umask_intr(dws, imask); 493552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang if (txint_level) 4947eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_writew(dws, DW_SPI_TXFLTR, txint_level); 495e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 496e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 1); 497e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (cs_change) 498e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->prev_chip = chip; 499e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 500e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 501e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (dws->dma_mapped) 5027063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang dws->dma_ops->dma_transfer(dws, cs_change); 503e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 504e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (chip->poll_mode) 505e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang poll_transfer(dws); 506e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 507e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return; 508e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 509e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangearly_exit: 510e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang giveback(dws); 511e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 512e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 513ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siachstatic int dw_spi_transfer_one_message(struct spi_master *master, 514ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach struct spi_message *msg) 515e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 516ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach struct dw_spi *dws = spi_master_get_devdata(master); 517e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 518ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach dws->cur_msg = msg; 519c3c6e231d860774037e7001ff3d536e5644fe2daAndy Shevchenko /* Initial message state */ 520e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_msg->state = START_STATE; 521e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_transfer = list_entry(dws->cur_msg->transfers.next, 522e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_transfer, 523e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang transfer_list); 524e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->cur_chip = spi_get_ctldata(dws->cur_msg->spi); 525e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 526ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach /* Launch transfers */ 527e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang tasklet_schedule(&dws->pump_transfers); 528e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 529e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return 0; 530e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 531e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 532e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang/* This may be called twice for each spi dev */ 533e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic int dw_spi_setup(struct spi_device *spi) 534e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 535e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct dw_spi_chip *chip_info = NULL; 536e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct chip_data *chip; 537d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach int ret; 538e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 539e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Only alloc on first setup */ 540e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip = spi_get_ctldata(spi); 541e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (!chip) { 542a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); 543e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (!chip) 544e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return -ENOMEM; 54543f627ac9de42607b2cdcc7a41f2bcc82187e06aBaruch Siach spi_set_ctldata(spi, chip); 546e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 547e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 548e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* 549e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * Protocol drivers may change the chip settings, so... 550e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang * if chip_info exists, use it 551e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang */ 552e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip_info = spi->controller_data; 553e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 554e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* chip_info doesn't always exist */ 555e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (chip_info) { 556e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (chip_info->cs_control) 557e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->cs_control = chip_info->cs_control; 558e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 559e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->poll_mode = chip_info->poll_mode; 560e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->type = chip_info->type; 561e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 562e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->rx_threshold = 0; 563e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->tx_threshold = 0; 564e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 565e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->enable_dma = chip_info->enable_dma; 566e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 567e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 56824778be20f87d5aadb19624fc768b3159fa43efcStephen Warren if (spi->bits_per_word == 8) { 569e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->n_bytes = 1; 570e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->dma_width = 1; 57124778be20f87d5aadb19624fc768b3159fa43efcStephen Warren } else if (spi->bits_per_word == 16) { 572e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->n_bytes = 2; 573e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->dma_width = 2; 574e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 575e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->bits_per_word = spi->bits_per_word; 576e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 577552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang if (!spi->max_speed_hz) { 578552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang dev_err(&spi->dev, "No max speed HZ parameter\n"); 579552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang return -EINVAL; 580552e450929a7298cc8834fd2824a60b2e914f70eFeng Tang } 581e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 582e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->tmode = 0; /* Tx & Rx */ 583e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Default SPI mode is SCPOL = 0, SCPH = 0 */ 584e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang chip->cr0 = (chip->bits_per_word - 1) 585e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang | (chip->type << SPI_FRF_OFFSET) 586e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang | (spi->mode << SPI_MODE_OFFSET) 587e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang | (chip->tmode << SPI_TMOD_OFFSET); 588e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 589c3ce15bf2ae5cde3392944ad043b80f123510cdeAndy Shevchenko if (spi->mode & SPI_LOOP) 590c3ce15bf2ae5cde3392944ad043b80f123510cdeAndy Shevchenko chip->cr0 |= 1 << SPI_SRL_OFFSET; 591c3ce15bf2ae5cde3392944ad043b80f123510cdeAndy Shevchenko 592d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach if (gpio_is_valid(spi->cs_gpio)) { 593d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach ret = gpio_direction_output(spi->cs_gpio, 594d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach !(spi->mode & SPI_CS_HIGH)); 595d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach if (ret) 596d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach return ret; 597d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach } 598d9c73bb8a3a5e4b76d2ad55da00d9ea776475c81Baruch Siach 599e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return 0; 600e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 601e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 602a97c883a16da7e0691a3be5465926c92a8da4da6Axel Linstatic void dw_spi_cleanup(struct spi_device *spi) 603a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin{ 604a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin struct chip_data *chip = spi_get_ctldata(spi); 605a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin 606a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin kfree(chip); 607a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin spi_set_ctldata(spi, NULL); 608a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin} 609a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin 610e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang/* Restart the controller, disable all interrupts, clean rx fifo */ 611e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangstatic void spi_hw_init(struct dw_spi *dws) 612e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 613e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 0); 614e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_mask_intr(dws, 0xff); 615e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 1); 616c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang 617c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang /* 618c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang * Try to detect the FIFO depth if not set by interface driver, 619c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang * the depth could be from 2 to 256 from HW spec 620c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang */ 621c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang if (!dws->fifo_len) { 622c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang u32 fifo; 623fadcace703bbb985a996d01141499bd8d1f7d5bcJingoo Han 624c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang for (fifo = 2; fifo <= 257; fifo++) { 6257eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_writew(dws, DW_SPI_TXFLTR, fifo); 6267eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten if (fifo != dw_readw(dws, DW_SPI_TXFLTR)) 627c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang break; 628c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang } 629c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang 630c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang dws->fifo_len = (fifo == 257) ? 0 : fifo; 6317eb187b3cd3f6f285d91a196dbefac9b6adbb07cH Hartley Sweeten dw_writew(dws, DW_SPI_TXFLTR, 0); 632c587b6fa05106606053fc5e8e344f07cd34ace23Feng Tang } 633e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 634e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 63504f421e7b0b10de3fae543dac4d324b449a1db6bBaruch Siachint dw_spi_add_host(struct device *dev, struct dw_spi *dws) 636e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 637e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang struct spi_master *master; 638e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang int ret; 639e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 640e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang BUG_ON(dws == NULL); 641e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 64204f421e7b0b10de3fae543dac4d324b449a1db6bBaruch Siach master = spi_alloc_master(dev, 0); 64304f421e7b0b10de3fae543dac4d324b449a1db6bBaruch Siach if (!master) 64404f421e7b0b10de3fae543dac4d324b449a1db6bBaruch Siach return -ENOMEM; 645e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 646e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->master = master; 647e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->type = SSI_MOTO_SPI; 648e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->prev_chip = NULL; 649e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->dma_inited = 0; 650e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dws->dma_addr = (dma_addr_t)(dws->paddr + 0x60); 651c3c6e231d860774037e7001ff3d536e5644fe2daAndy Shevchenko snprintf(dws->name, sizeof(dws->name), "dw_spi%d", dws->bus_num); 652e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 65304f421e7b0b10de3fae543dac4d324b449a1db6bBaruch Siach ret = devm_request_irq(dev, dws->irq, dw_spi_irq, IRQF_SHARED, 65440bfff85ffb5c85ffabcb6d71e64f70799595f89Liu, ShuoX dws->name, dws); 655e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (ret < 0) { 656e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dev_err(&master->dev, "can not get IRQ\n"); 657e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang goto err_free_master; 658e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 659e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 660c3ce15bf2ae5cde3392944ad043b80f123510cdeAndy Shevchenko master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP; 66124778be20f87d5aadb19624fc768b3159fa43efcStephen Warren master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16); 662e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang master->bus_num = dws->bus_num; 663e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang master->num_chipselect = dws->num_cs; 664e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang master->setup = dw_spi_setup; 665a97c883a16da7e0691a3be5465926c92a8da4da6Axel Lin master->cleanup = dw_spi_cleanup; 666ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach master->transfer_one_message = dw_spi_transfer_one_message; 667765ee709eb40abf0c43c6d864ac6f01677b7fd5aAxel Lin master->max_speed_hz = dws->max_freq; 6689c6de47d53a3ce8df1642ae67823688eb98a190aThor Thayer master->dev.of_node = dev->of_node; 669e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 670e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Basic HW init */ 671e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_hw_init(dws); 672e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 6737063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang if (dws->dma_ops && dws->dma_ops->dma_init) { 6747063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang ret = dws->dma_ops->dma_init(dws); 6757063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang if (ret) { 6767063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang dev_warn(&master->dev, "DMA init failed\n"); 6777063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang dws->dma_inited = 0; 6787063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang } 6797063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang } 6807063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang 681ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach tasklet_init(&dws->pump_transfers, pump_transfers, (unsigned long)dws); 682e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 683e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_master_set_devdata(master, dws); 68404f421e7b0b10de3fae543dac4d324b449a1db6bBaruch Siach ret = devm_spi_register_master(dev, master); 685e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (ret) { 686e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dev_err(&master->dev, "problem registering spi master\n"); 687ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach goto err_dma_exit; 688e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang } 689e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 69053288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko dw_spi_debugfs_init(dws); 691e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return 0; 692e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 693ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siacherr_dma_exit: 6947063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang if (dws->dma_ops && dws->dma_ops->dma_exit) 6957063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang dws->dma_ops->dma_exit(dws); 696e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 0); 697e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangerr_free_master: 698e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_master_put(master); 699e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return ret; 700e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 70179290a2aa2fd1c179a285218472092475630dc0eFeng TangEXPORT_SYMBOL_GPL(dw_spi_add_host); 702e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 703fd4a319bc933ae93e68935b21924a9ca4ba2d060Grant Likelyvoid dw_spi_remove_host(struct dw_spi *dws) 704e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 705e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (!dws) 706e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return; 70753288fe9bdc7e8a0265bbe9074f71f1a6c478008Andy Shevchenko dw_spi_debugfs_remove(dws); 708e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 7097063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang if (dws->dma_ops && dws->dma_ops->dma_exit) 7107063c0d942a1af2993531fbe52b4c74c1db818c4Feng Tang dws->dma_ops->dma_exit(dws); 711e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 0); 712e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang /* Disable clk */ 713e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_set_clk(dws, 0); 714e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 71579290a2aa2fd1c179a285218472092475630dc0eFeng TangEXPORT_SYMBOL_GPL(dw_spi_remove_host); 716e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 717e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangint dw_spi_suspend_host(struct dw_spi *dws) 718e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 719e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang int ret = 0; 720e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 721ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach ret = spi_master_suspend(dws->master); 722e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (ret) 723e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return ret; 724e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_enable_chip(dws, 0); 725e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_set_clk(dws, 0); 726e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return ret; 727e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 72879290a2aa2fd1c179a285218472092475630dc0eFeng TangEXPORT_SYMBOL_GPL(dw_spi_suspend_host); 729e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 730e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tangint dw_spi_resume_host(struct dw_spi *dws) 731e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang{ 732e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang int ret; 733e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 734e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang spi_hw_init(dws); 735ec37e8e1f0e376776dde5e9539af414d2ec31f71Baruch Siach ret = spi_master_resume(dws->master); 736e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang if (ret) 737e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret); 738e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang return ret; 739e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang} 74079290a2aa2fd1c179a285218472092475630dc0eFeng TangEXPORT_SYMBOL_GPL(dw_spi_resume_host); 741e24c745272072fd2abe55209f1949b7b7ee602a7Feng Tang 742e24c745272072fd2abe55209f1949b7b7ee602a7Feng TangMODULE_AUTHOR("Feng Tang <feng.tang@intel.com>"); 743e24c745272072fd2abe55209f1949b7b7ee602a7Feng TangMODULE_DESCRIPTION("Driver for DesignWare SPI controller core"); 744e24c745272072fd2abe55209f1949b7b7ee602a7Feng TangMODULE_LICENSE("GPL v2"); 745