1b0823ee3SMasahisa Kojima // SPDX-License-Identifier: GPL-2.0 2b0823ee3SMasahisa Kojima // 3b0823ee3SMasahisa Kojima // Synquacer HSSPI controller driver 4b0823ee3SMasahisa Kojima // 5b0823ee3SMasahisa Kojima // Copyright (c) 2015-2018 Socionext Inc. 6b0823ee3SMasahisa Kojima // Copyright (c) 2018-2019 Linaro Ltd. 7b0823ee3SMasahisa Kojima // 8b0823ee3SMasahisa Kojima 9b0823ee3SMasahisa Kojima #include <linux/acpi.h> 10b0823ee3SMasahisa Kojima #include <linux/delay.h> 11b0823ee3SMasahisa Kojima #include <linux/interrupt.h> 12b0823ee3SMasahisa Kojima #include <linux/io.h> 13b0823ee3SMasahisa Kojima #include <linux/module.h> 14b0823ee3SMasahisa Kojima #include <linux/of.h> 15b0823ee3SMasahisa Kojima #include <linux/platform_device.h> 16b0823ee3SMasahisa Kojima #include <linux/pm_runtime.h> 17b0823ee3SMasahisa Kojima #include <linux/scatterlist.h> 18b0823ee3SMasahisa Kojima #include <linux/slab.h> 19b0823ee3SMasahisa Kojima #include <linux/spi/spi.h> 20b0823ee3SMasahisa Kojima #include <linux/spinlock.h> 21b0823ee3SMasahisa Kojima #include <linux/clk.h> 22b0823ee3SMasahisa Kojima 23b0823ee3SMasahisa Kojima /* HSSPI register address definitions */ 24b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_MCTRL 0x00 25b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_PCC0 0x04 26b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_PCC(n) (SYNQUACER_HSSPI_REG_PCC0 + (n) * 4) 27b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TXF 0x14 28b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TXE 0x18 29b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TXC 0x1C 30b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RXF 0x20 31b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RXE 0x24 32b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RXC 0x28 33b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_FAULTF 0x2C 34b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_FAULTC 0x30 35b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMCFG 0x34 36b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMSTART 0x38 37b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMBCC 0x3C 38b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_DMSTATUS 0x40 39b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_FIFOCFG 0x4C 40b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_TX_FIFO 0x50 41b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_RX_FIFO 0x90 42b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_REG_MID 0xFC 43b0823ee3SMasahisa Kojima 44b0823ee3SMasahisa Kojima /* HSSPI register bit definitions */ 45b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_MEN BIT(0) 46b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN BIT(1) 47b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_CDSS BIT(3) 48b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_MES BIT(4) 49b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_MCTRL_SYNCON BIT(5) 50b0823ee3SMasahisa Kojima 51b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CPHA BIT(0) 52b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CPOL BIT(1) 53b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_ACES BIT(2) 54b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_RTM BIT(3) 55b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SSPOL BIT(4) 56b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SDIR BIT(7) 57b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SENDIAN BIT(8) 58b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SAFESYNC BIT(16) 59b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_SS2CD_SHIFT 5U 60b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CDRS_MASK 0x7f 61b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_PCC_CDRS_SHIFT 9U 62b0823ee3SMasahisa Kojima 63b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXF_FIFO_FULL BIT(0) 64b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXF_FIFO_EMPTY BIT(1) 65b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXF_SLAVE_RELEASED BIT(6) 66b0823ee3SMasahisa Kojima 67b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXE_FIFO_FULL BIT(0) 68b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXE_FIFO_EMPTY BIT(1) 69b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TXE_SLAVE_RELEASED BIT(6) 70b0823ee3SMasahisa Kojima 71b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD BIT(5) 72b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXF_SLAVE_RELEASED BIT(6) 73b0823ee3SMasahisa Kojima 74b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD BIT(5) 75b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_RXE_SLAVE_RELEASED BIT(6) 76b0823ee3SMasahisa Kojima 77b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMCFG_SSDC BIT(1) 78b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMCFG_MSTARTEN BIT(2) 79b0823ee3SMasahisa Kojima 80b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTART_START BIT(0) 81b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTOP_STOP BIT(8) 82b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMPSEL_CS_MASK 0x3 83b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMPSEL_CS_SHIFT 16U 84b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT 24U 85b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_MASK 0x3 86b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_SHIFT 26U 87b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_TXRX 0 88b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_RX 1 89b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMTRP_DATA_TX 2 90b0823ee3SMasahisa Kojima 91b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK 0x1f 92b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT 8U 93b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK 0x1f 94b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT 16U 95b0823ee3SMasahisa Kojima 96b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK 0xf 97b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT 0U 98b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_MASK 0xf 99b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_TX_THRESHOLD_SHIFT 4U 100b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK 0x3 101b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT 8U 102b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH BIT(11) 103b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH BIT(12) 104b0823ee3SMasahisa Kojima 105b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFO_DEPTH 16U 106b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFO_TX_THRESHOLD 4U 107b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_FIFO_RX_THRESHOLD \ 108b0823ee3SMasahisa Kojima (SYNQUACER_HSSPI_FIFO_DEPTH - SYNQUACER_HSSPI_FIFO_TX_THRESHOLD) 109b0823ee3SMasahisa Kojima 110b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TRANSFER_MODE_TX BIT(1) 111b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TRANSFER_MODE_RX BIT(2) 112b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC 2000U 113b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC 1000U 114b0823ee3SMasahisa Kojima 115b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_CLOCK_SRC_IHCLK 0 116b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_CLOCK_SRC_IPCLK 1 117b0823ee3SMasahisa Kojima 118b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_NUM_CHIP_SELECT 4U 119b0823ee3SMasahisa Kojima #define SYNQUACER_HSSPI_IRQ_NAME_MAX 32U 120b0823ee3SMasahisa Kojima 121b0823ee3SMasahisa Kojima struct synquacer_spi { 122b0823ee3SMasahisa Kojima struct device *dev; 123b0823ee3SMasahisa Kojima struct completion transfer_done; 124b0823ee3SMasahisa Kojima unsigned int cs; 125b0823ee3SMasahisa Kojima unsigned int bpw; 126b0823ee3SMasahisa Kojima unsigned int mode; 127b0823ee3SMasahisa Kojima unsigned int speed; 128b0823ee3SMasahisa Kojima bool aces, rtm; 129b0823ee3SMasahisa Kojima void *rx_buf; 130b0823ee3SMasahisa Kojima const void *tx_buf; 131b0823ee3SMasahisa Kojima struct clk *clk; 132b0823ee3SMasahisa Kojima int clk_src_type; 133b0823ee3SMasahisa Kojima void __iomem *regs; 134b0823ee3SMasahisa Kojima u32 tx_words, rx_words; 135b0823ee3SMasahisa Kojima unsigned int bus_width; 136b0823ee3SMasahisa Kojima unsigned int transfer_mode; 137b0823ee3SMasahisa Kojima char rx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX]; 138b0823ee3SMasahisa Kojima char tx_irq_name[SYNQUACER_HSSPI_IRQ_NAME_MAX]; 139b0823ee3SMasahisa Kojima }; 140b0823ee3SMasahisa Kojima 141b0823ee3SMasahisa Kojima static int read_fifo(struct synquacer_spi *sspi) 142b0823ee3SMasahisa Kojima { 143b0823ee3SMasahisa Kojima u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS); 144b0823ee3SMasahisa Kojima 145b0823ee3SMasahisa Kojima len = (len >> SYNQUACER_HSSPI_DMSTATUS_RX_DATA_SHIFT) & 146b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_DMSTATUS_RX_DATA_MASK; 147b0823ee3SMasahisa Kojima len = min(len, sspi->rx_words); 148b0823ee3SMasahisa Kojima 149b0823ee3SMasahisa Kojima switch (sspi->bpw) { 150b0823ee3SMasahisa Kojima case 8: { 151b0823ee3SMasahisa Kojima u8 *buf = sspi->rx_buf; 152b0823ee3SMasahisa Kojima 15351c711f2SMasahisa Kojima ioread8_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, 15451c711f2SMasahisa Kojima buf, len); 155b0823ee3SMasahisa Kojima sspi->rx_buf = buf + len; 156b0823ee3SMasahisa Kojima break; 157b0823ee3SMasahisa Kojima } 158b0823ee3SMasahisa Kojima case 16: { 159b0823ee3SMasahisa Kojima u16 *buf = sspi->rx_buf; 160b0823ee3SMasahisa Kojima 16151c711f2SMasahisa Kojima ioread16_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, 16251c711f2SMasahisa Kojima buf, len); 163b0823ee3SMasahisa Kojima sspi->rx_buf = buf + len; 164b0823ee3SMasahisa Kojima break; 165b0823ee3SMasahisa Kojima } 166b0823ee3SMasahisa Kojima case 24: 167b0823ee3SMasahisa Kojima /* fallthrough, should use 32-bits access */ 168b0823ee3SMasahisa Kojima case 32: { 169b0823ee3SMasahisa Kojima u32 *buf = sspi->rx_buf; 170b0823ee3SMasahisa Kojima 17151c711f2SMasahisa Kojima ioread32_rep(sspi->regs + SYNQUACER_HSSPI_REG_RX_FIFO, 17251c711f2SMasahisa Kojima buf, len); 173b0823ee3SMasahisa Kojima sspi->rx_buf = buf + len; 174b0823ee3SMasahisa Kojima break; 175b0823ee3SMasahisa Kojima } 176b0823ee3SMasahisa Kojima default: 177b0823ee3SMasahisa Kojima return -EINVAL; 178b0823ee3SMasahisa Kojima } 179b0823ee3SMasahisa Kojima 180b0823ee3SMasahisa Kojima sspi->rx_words -= len; 181b0823ee3SMasahisa Kojima return 0; 182b0823ee3SMasahisa Kojima } 183b0823ee3SMasahisa Kojima 184b0823ee3SMasahisa Kojima static int write_fifo(struct synquacer_spi *sspi) 185b0823ee3SMasahisa Kojima { 186b0823ee3SMasahisa Kojima u32 len = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTATUS); 187b0823ee3SMasahisa Kojima 188b0823ee3SMasahisa Kojima len = (len >> SYNQUACER_HSSPI_DMSTATUS_TX_DATA_SHIFT) & 189b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_DMSTATUS_TX_DATA_MASK; 190b0823ee3SMasahisa Kojima len = min(SYNQUACER_HSSPI_FIFO_DEPTH - len, 191b0823ee3SMasahisa Kojima sspi->tx_words); 192b0823ee3SMasahisa Kojima 193b0823ee3SMasahisa Kojima switch (sspi->bpw) { 194b0823ee3SMasahisa Kojima case 8: { 195b0823ee3SMasahisa Kojima const u8 *buf = sspi->tx_buf; 196b0823ee3SMasahisa Kojima 19751c711f2SMasahisa Kojima iowrite8_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, 19851c711f2SMasahisa Kojima buf, len); 199b0823ee3SMasahisa Kojima sspi->tx_buf = buf + len; 200b0823ee3SMasahisa Kojima break; 201b0823ee3SMasahisa Kojima } 202b0823ee3SMasahisa Kojima case 16: { 203b0823ee3SMasahisa Kojima const u16 *buf = sspi->tx_buf; 204b0823ee3SMasahisa Kojima 20551c711f2SMasahisa Kojima iowrite16_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, 20651c711f2SMasahisa Kojima buf, len); 207b0823ee3SMasahisa Kojima sspi->tx_buf = buf + len; 208b0823ee3SMasahisa Kojima break; 209b0823ee3SMasahisa Kojima } 210b0823ee3SMasahisa Kojima case 24: 211b0823ee3SMasahisa Kojima /* fallthrough, should use 32-bits access */ 212b0823ee3SMasahisa Kojima case 32: { 213b0823ee3SMasahisa Kojima const u32 *buf = sspi->tx_buf; 214b0823ee3SMasahisa Kojima 21551c711f2SMasahisa Kojima iowrite32_rep(sspi->regs + SYNQUACER_HSSPI_REG_TX_FIFO, 21651c711f2SMasahisa Kojima buf, len); 217b0823ee3SMasahisa Kojima sspi->tx_buf = buf + len; 218b0823ee3SMasahisa Kojima break; 219b0823ee3SMasahisa Kojima } 220b0823ee3SMasahisa Kojima default: 221b0823ee3SMasahisa Kojima return -EINVAL; 222b0823ee3SMasahisa Kojima } 223b0823ee3SMasahisa Kojima 224b0823ee3SMasahisa Kojima sspi->tx_words -= len; 225b0823ee3SMasahisa Kojima return 0; 226b0823ee3SMasahisa Kojima } 227b0823ee3SMasahisa Kojima 228b0823ee3SMasahisa Kojima static int synquacer_spi_config(struct spi_master *master, 229b0823ee3SMasahisa Kojima struct spi_device *spi, 230b0823ee3SMasahisa Kojima struct spi_transfer *xfer) 231b0823ee3SMasahisa Kojima { 232b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = spi_master_get_devdata(master); 233b0823ee3SMasahisa Kojima unsigned int speed, mode, bpw, cs, bus_width, transfer_mode; 234b0823ee3SMasahisa Kojima u32 rate, val, div; 235b0823ee3SMasahisa Kojima 236b0823ee3SMasahisa Kojima /* Full Duplex only on 1-bit wide bus */ 237b0823ee3SMasahisa Kojima if (xfer->rx_buf && xfer->tx_buf && 238b0823ee3SMasahisa Kojima (xfer->rx_nbits != 1 || xfer->tx_nbits != 1)) { 239b0823ee3SMasahisa Kojima dev_err(sspi->dev, 240b0823ee3SMasahisa Kojima "RX and TX bus widths must be 1-bit for Full-Duplex!\n"); 241b0823ee3SMasahisa Kojima return -EINVAL; 242b0823ee3SMasahisa Kojima } 243b0823ee3SMasahisa Kojima 244b0823ee3SMasahisa Kojima if (xfer->tx_buf) { 245b0823ee3SMasahisa Kojima bus_width = xfer->tx_nbits; 246b0823ee3SMasahisa Kojima transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_TX; 247b0823ee3SMasahisa Kojima } else { 248b0823ee3SMasahisa Kojima bus_width = xfer->rx_nbits; 249b0823ee3SMasahisa Kojima transfer_mode = SYNQUACER_HSSPI_TRANSFER_MODE_RX; 250b0823ee3SMasahisa Kojima } 251b0823ee3SMasahisa Kojima 252b0823ee3SMasahisa Kojima mode = spi->mode; 253b0823ee3SMasahisa Kojima cs = spi->chip_select; 254b0823ee3SMasahisa Kojima speed = xfer->speed_hz; 255b0823ee3SMasahisa Kojima bpw = xfer->bits_per_word; 256b0823ee3SMasahisa Kojima 257b0823ee3SMasahisa Kojima /* return if nothing to change */ 258b0823ee3SMasahisa Kojima if (speed == sspi->speed && 259b0823ee3SMasahisa Kojima bus_width == sspi->bus_width && bpw == sspi->bpw && 260b0823ee3SMasahisa Kojima mode == sspi->mode && cs == sspi->cs && 261b0823ee3SMasahisa Kojima transfer_mode == sspi->transfer_mode) { 262b0823ee3SMasahisa Kojima return 0; 263b0823ee3SMasahisa Kojima } 264b0823ee3SMasahisa Kojima 265b0823ee3SMasahisa Kojima sspi->transfer_mode = transfer_mode; 266b0823ee3SMasahisa Kojima rate = master->max_speed_hz; 267b0823ee3SMasahisa Kojima 268b0823ee3SMasahisa Kojima div = DIV_ROUND_UP(rate, speed); 269b0823ee3SMasahisa Kojima if (div > 254) { 270b0823ee3SMasahisa Kojima dev_err(sspi->dev, "Requested rate too low (%u)\n", 271b0823ee3SMasahisa Kojima sspi->speed); 272b0823ee3SMasahisa Kojima return -EINVAL; 273b0823ee3SMasahisa Kojima } 274b0823ee3SMasahisa Kojima 275b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs)); 276b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_PCC_SAFESYNC; 277b0823ee3SMasahisa Kojima if (bpw == 8 && (mode & (SPI_TX_DUAL | SPI_RX_DUAL)) && div < 3) 278b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_SAFESYNC; 279b0823ee3SMasahisa Kojima if (bpw == 8 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 6) 280b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_SAFESYNC; 281b0823ee3SMasahisa Kojima if (bpw == 16 && (mode & (SPI_TX_QUAD | SPI_RX_QUAD)) && div < 3) 282b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_SAFESYNC; 283b0823ee3SMasahisa Kojima 284b0823ee3SMasahisa Kojima if (mode & SPI_CPHA) 285b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_CPHA; 286b0823ee3SMasahisa Kojima else 287b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_PCC_CPHA; 288b0823ee3SMasahisa Kojima 289b0823ee3SMasahisa Kojima if (mode & SPI_CPOL) 290b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_CPOL; 291b0823ee3SMasahisa Kojima else 292b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_PCC_CPOL; 293b0823ee3SMasahisa Kojima 294b0823ee3SMasahisa Kojima if (mode & SPI_CS_HIGH) 295b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_SSPOL; 296b0823ee3SMasahisa Kojima else 297b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_PCC_SSPOL; 298b0823ee3SMasahisa Kojima 299b0823ee3SMasahisa Kojima if (mode & SPI_LSB_FIRST) 300b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_SDIR; 301b0823ee3SMasahisa Kojima else 302b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_PCC_SDIR; 303b0823ee3SMasahisa Kojima 304b0823ee3SMasahisa Kojima if (sspi->aces) 305b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_ACES; 306b0823ee3SMasahisa Kojima else 307b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_PCC_ACES; 308b0823ee3SMasahisa Kojima 309b0823ee3SMasahisa Kojima if (sspi->rtm) 310b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_RTM; 311b0823ee3SMasahisa Kojima else 312b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_PCC_RTM; 313b0823ee3SMasahisa Kojima 314b0823ee3SMasahisa Kojima val |= (3 << SYNQUACER_HSSPI_PCC_SS2CD_SHIFT); 315b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_PCC_SENDIAN; 316b0823ee3SMasahisa Kojima 317b0823ee3SMasahisa Kojima val &= ~(SYNQUACER_HSSPI_PCC_CDRS_MASK << 318b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_PCC_CDRS_SHIFT); 319b0823ee3SMasahisa Kojima val |= ((div >> 1) << SYNQUACER_HSSPI_PCC_CDRS_SHIFT); 320b0823ee3SMasahisa Kojima 321b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_PCC(cs)); 322b0823ee3SMasahisa Kojima 323b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); 324b0823ee3SMasahisa Kojima val &= ~(SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_MASK << 325b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT); 326b0823ee3SMasahisa Kojima val |= ((bpw / 8 - 1) << SYNQUACER_HSSPI_FIFOCFG_FIFO_WIDTH_SHIFT); 327b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); 328b0823ee3SMasahisa Kojima 329b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 330b0823ee3SMasahisa Kojima val &= ~(SYNQUACER_HSSPI_DMTRP_DATA_MASK << 331b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); 332b0823ee3SMasahisa Kojima 333b0823ee3SMasahisa Kojima if (xfer->rx_buf) 334b0823ee3SMasahisa Kojima val |= (SYNQUACER_HSSPI_DMTRP_DATA_RX << 335b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); 336b0823ee3SMasahisa Kojima else 337b0823ee3SMasahisa Kojima val |= (SYNQUACER_HSSPI_DMTRP_DATA_TX << 338b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_DMTRP_DATA_SHIFT); 339b0823ee3SMasahisa Kojima 340b0823ee3SMasahisa Kojima val &= ~(3 << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT); 341b0823ee3SMasahisa Kojima val |= ((bus_width >> 1) << SYNQUACER_HSSPI_DMTRP_BUS_WIDTH_SHIFT); 342b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 343b0823ee3SMasahisa Kojima 344b0823ee3SMasahisa Kojima sspi->bpw = bpw; 345b0823ee3SMasahisa Kojima sspi->mode = mode; 346b0823ee3SMasahisa Kojima sspi->speed = speed; 347b0823ee3SMasahisa Kojima sspi->cs = spi->chip_select; 348b0823ee3SMasahisa Kojima sspi->bus_width = bus_width; 349b0823ee3SMasahisa Kojima 350b0823ee3SMasahisa Kojima return 0; 351b0823ee3SMasahisa Kojima } 352b0823ee3SMasahisa Kojima 353b0823ee3SMasahisa Kojima static int synquacer_spi_transfer_one(struct spi_master *master, 354b0823ee3SMasahisa Kojima struct spi_device *spi, 355b0823ee3SMasahisa Kojima struct spi_transfer *xfer) 356b0823ee3SMasahisa Kojima { 357b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = spi_master_get_devdata(master); 358b0823ee3SMasahisa Kojima int ret; 359b0823ee3SMasahisa Kojima int status = 0; 360b0823ee3SMasahisa Kojima u32 words; 361b0823ee3SMasahisa Kojima u8 bpw; 362b0823ee3SMasahisa Kojima u32 val; 363b0823ee3SMasahisa Kojima 364b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 365b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_DMSTOP_STOP; 366b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 367b0823ee3SMasahisa Kojima 368b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); 369b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_FIFOCFG_RX_FLUSH; 370b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_FIFOCFG_TX_FLUSH; 371b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); 372b0823ee3SMasahisa Kojima 373b0823ee3SMasahisa Kojima /* 374b0823ee3SMasahisa Kojima * See if we can transfer 4-bytes as 1 word 375b0823ee3SMasahisa Kojima * to maximize the FIFO buffer efficiency. 376b0823ee3SMasahisa Kojima */ 377b0823ee3SMasahisa Kojima bpw = xfer->bits_per_word; 378b0823ee3SMasahisa Kojima if (bpw == 8 && !(xfer->len % 4) && !(spi->mode & SPI_LSB_FIRST)) 379b0823ee3SMasahisa Kojima xfer->bits_per_word = 32; 380b0823ee3SMasahisa Kojima 381b0823ee3SMasahisa Kojima ret = synquacer_spi_config(master, spi, xfer); 382b0823ee3SMasahisa Kojima 383b0823ee3SMasahisa Kojima /* restore */ 384b0823ee3SMasahisa Kojima xfer->bits_per_word = bpw; 385b0823ee3SMasahisa Kojima 386b0823ee3SMasahisa Kojima if (ret) 387b0823ee3SMasahisa Kojima return ret; 388b0823ee3SMasahisa Kojima 389b0823ee3SMasahisa Kojima reinit_completion(&sspi->transfer_done); 390b0823ee3SMasahisa Kojima 391b0823ee3SMasahisa Kojima sspi->tx_buf = xfer->tx_buf; 392b0823ee3SMasahisa Kojima sspi->rx_buf = xfer->rx_buf; 393b0823ee3SMasahisa Kojima 394b0823ee3SMasahisa Kojima switch (sspi->bpw) { 395b0823ee3SMasahisa Kojima case 8: 396b0823ee3SMasahisa Kojima words = xfer->len; 397b0823ee3SMasahisa Kojima break; 398b0823ee3SMasahisa Kojima case 16: 399b0823ee3SMasahisa Kojima words = xfer->len / 2; 400b0823ee3SMasahisa Kojima break; 401b0823ee3SMasahisa Kojima case 24: 402b0823ee3SMasahisa Kojima /* fallthrough, should use 32-bits access */ 403b0823ee3SMasahisa Kojima case 32: 404b0823ee3SMasahisa Kojima words = xfer->len / 4; 405b0823ee3SMasahisa Kojima break; 406b0823ee3SMasahisa Kojima default: 407b0823ee3SMasahisa Kojima dev_err(sspi->dev, "unsupported bpw: %d\n", sspi->bpw); 408b0823ee3SMasahisa Kojima return -EINVAL; 409b0823ee3SMasahisa Kojima } 410b0823ee3SMasahisa Kojima 411b0823ee3SMasahisa Kojima if (xfer->tx_buf) 412b0823ee3SMasahisa Kojima sspi->tx_words = words; 413b0823ee3SMasahisa Kojima else 414b0823ee3SMasahisa Kojima sspi->tx_words = 0; 415b0823ee3SMasahisa Kojima 416b0823ee3SMasahisa Kojima if (xfer->rx_buf) 417b0823ee3SMasahisa Kojima sspi->rx_words = words; 418b0823ee3SMasahisa Kojima else 419b0823ee3SMasahisa Kojima sspi->rx_words = 0; 420b0823ee3SMasahisa Kojima 421b0823ee3SMasahisa Kojima if (xfer->tx_buf) { 422b0823ee3SMasahisa Kojima status = write_fifo(sspi); 423b0823ee3SMasahisa Kojima if (status < 0) { 424b0823ee3SMasahisa Kojima dev_err(sspi->dev, "failed write_fifo. status: 0x%x\n", 425b0823ee3SMasahisa Kojima status); 426b0823ee3SMasahisa Kojima return status; 427b0823ee3SMasahisa Kojima } 428b0823ee3SMasahisa Kojima } 429b0823ee3SMasahisa Kojima 430b0823ee3SMasahisa Kojima if (xfer->rx_buf) { 431b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); 432b0823ee3SMasahisa Kojima val &= ~(SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_MASK << 433b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT); 434b0823ee3SMasahisa Kojima val |= ((sspi->rx_words > SYNQUACER_HSSPI_FIFO_DEPTH ? 435b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_FIFO_RX_THRESHOLD : sspi->rx_words) << 436b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_FIFOCFG_RX_THRESHOLD_SHIFT); 437b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_FIFOCFG); 438b0823ee3SMasahisa Kojima } 439b0823ee3SMasahisa Kojima 440b0823ee3SMasahisa Kojima writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC); 441b0823ee3SMasahisa Kojima writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC); 442b0823ee3SMasahisa Kojima 443b0823ee3SMasahisa Kojima /* Trigger */ 444b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 445b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_DMSTART_START; 446b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 447b0823ee3SMasahisa Kojima 448b0823ee3SMasahisa Kojima if (xfer->tx_buf) { 449b0823ee3SMasahisa Kojima val = SYNQUACER_HSSPI_TXE_FIFO_EMPTY; 450b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_TXE); 451b0823ee3SMasahisa Kojima status = wait_for_completion_timeout(&sspi->transfer_done, 452b0823ee3SMasahisa Kojima msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC)); 453b0823ee3SMasahisa Kojima writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); 454b0823ee3SMasahisa Kojima } 455b0823ee3SMasahisa Kojima 456b0823ee3SMasahisa Kojima if (xfer->rx_buf) { 457b0823ee3SMasahisa Kojima u32 buf[SYNQUACER_HSSPI_FIFO_DEPTH]; 458b0823ee3SMasahisa Kojima 459b0823ee3SMasahisa Kojima val = SYNQUACER_HSSPI_RXE_FIFO_MORE_THAN_THRESHOLD | 460b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_RXE_SLAVE_RELEASED; 461b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_RXE); 462b0823ee3SMasahisa Kojima status = wait_for_completion_timeout(&sspi->transfer_done, 463b0823ee3SMasahisa Kojima msecs_to_jiffies(SYNQUACER_HSSPI_TRANSFER_TMOUT_MSEC)); 464b0823ee3SMasahisa Kojima writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); 465b0823ee3SMasahisa Kojima 466b0823ee3SMasahisa Kojima /* stop RX and clean RXFIFO */ 467b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 468b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_DMSTOP_STOP; 469b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 470b0823ee3SMasahisa Kojima sspi->rx_buf = buf; 471b0823ee3SMasahisa Kojima sspi->rx_words = SYNQUACER_HSSPI_FIFO_DEPTH; 472b0823ee3SMasahisa Kojima read_fifo(sspi); 473b0823ee3SMasahisa Kojima } 474b0823ee3SMasahisa Kojima 475b0823ee3SMasahisa Kojima if (status < 0) { 476b0823ee3SMasahisa Kojima dev_err(sspi->dev, "failed to transfer. status: 0x%x\n", 477b0823ee3SMasahisa Kojima status); 478b0823ee3SMasahisa Kojima return status; 479b0823ee3SMasahisa Kojima } 480b0823ee3SMasahisa Kojima 481b0823ee3SMasahisa Kojima return 0; 482b0823ee3SMasahisa Kojima } 483b0823ee3SMasahisa Kojima 484b0823ee3SMasahisa Kojima static void synquacer_spi_set_cs(struct spi_device *spi, bool enable) 485b0823ee3SMasahisa Kojima { 486b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = spi_master_get_devdata(spi->master); 487b0823ee3SMasahisa Kojima u32 val; 488b0823ee3SMasahisa Kojima 489b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 490b0823ee3SMasahisa Kojima val &= ~(SYNQUACER_HSSPI_DMPSEL_CS_MASK << 491b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_DMPSEL_CS_SHIFT); 492b0823ee3SMasahisa Kojima val |= spi->chip_select << SYNQUACER_HSSPI_DMPSEL_CS_SHIFT; 4931c9f1750SMasahisa Kojima 4941c9f1750SMasahisa Kojima if (!enable) 4951c9f1750SMasahisa Kojima val |= SYNQUACER_HSSPI_DMSTOP_STOP; 4961c9f1750SMasahisa Kojima 497b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMSTART); 498b0823ee3SMasahisa Kojima } 499b0823ee3SMasahisa Kojima 500b0823ee3SMasahisa Kojima static int synquacer_spi_wait_status_update(struct synquacer_spi *sspi, 501b0823ee3SMasahisa Kojima bool enable) 502b0823ee3SMasahisa Kojima { 503b0823ee3SMasahisa Kojima u32 val; 504b0823ee3SMasahisa Kojima unsigned long timeout = jiffies + 505b0823ee3SMasahisa Kojima msecs_to_jiffies(SYNQUACER_HSSPI_ENABLE_TMOUT_MSEC); 506b0823ee3SMasahisa Kojima 507b0823ee3SMasahisa Kojima /* wait MES(Module Enable Status) is updated */ 508b0823ee3SMasahisa Kojima do { 509b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL) & 510b0823ee3SMasahisa Kojima SYNQUACER_HSSPI_MCTRL_MES; 511b0823ee3SMasahisa Kojima if (enable && val) 512b0823ee3SMasahisa Kojima return 0; 513b0823ee3SMasahisa Kojima if (!enable && !val) 514b0823ee3SMasahisa Kojima return 0; 515b0823ee3SMasahisa Kojima } while (time_before(jiffies, timeout)); 516b0823ee3SMasahisa Kojima 517b0823ee3SMasahisa Kojima dev_err(sspi->dev, "timeout occurs in updating Module Enable Status\n"); 518b0823ee3SMasahisa Kojima return -EBUSY; 519b0823ee3SMasahisa Kojima } 520b0823ee3SMasahisa Kojima 521b0823ee3SMasahisa Kojima static int synquacer_spi_enable(struct spi_master *master) 522b0823ee3SMasahisa Kojima { 523b0823ee3SMasahisa Kojima u32 val; 524b0823ee3SMasahisa Kojima int status; 525b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = spi_master_get_devdata(master); 526b0823ee3SMasahisa Kojima 527b0823ee3SMasahisa Kojima /* Disable module */ 528b0823ee3SMasahisa Kojima writel(0, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); 529b0823ee3SMasahisa Kojima status = synquacer_spi_wait_status_update(sspi, false); 530b0823ee3SMasahisa Kojima if (status < 0) 531b0823ee3SMasahisa Kojima return status; 532b0823ee3SMasahisa Kojima 533b0823ee3SMasahisa Kojima writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); 534b0823ee3SMasahisa Kojima writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); 535b0823ee3SMasahisa Kojima writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_TXC); 536b0823ee3SMasahisa Kojima writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_RXC); 537b0823ee3SMasahisa Kojima writel(~0, sspi->regs + SYNQUACER_HSSPI_REG_FAULTC); 538b0823ee3SMasahisa Kojima 539b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_DMCFG); 540b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_DMCFG_SSDC; 541b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_DMCFG_MSTARTEN; 542b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_DMCFG); 543b0823ee3SMasahisa Kojima 544b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); 545b0823ee3SMasahisa Kojima if (sspi->clk_src_type == SYNQUACER_HSSPI_CLOCK_SRC_IPCLK) 546b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_MCTRL_CDSS; 547b0823ee3SMasahisa Kojima else 548b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_MCTRL_CDSS; 549b0823ee3SMasahisa Kojima 550b0823ee3SMasahisa Kojima val &= ~SYNQUACER_HSSPI_MCTRL_COMMAND_SEQUENCE_EN; 551b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_MCTRL_MEN; 552b0823ee3SMasahisa Kojima val |= SYNQUACER_HSSPI_MCTRL_SYNCON; 553b0823ee3SMasahisa Kojima 554b0823ee3SMasahisa Kojima /* Enable module */ 555b0823ee3SMasahisa Kojima writel(val, sspi->regs + SYNQUACER_HSSPI_REG_MCTRL); 556b0823ee3SMasahisa Kojima status = synquacer_spi_wait_status_update(sspi, true); 557b0823ee3SMasahisa Kojima if (status < 0) 558b0823ee3SMasahisa Kojima return status; 559b0823ee3SMasahisa Kojima 560b0823ee3SMasahisa Kojima return 0; 561b0823ee3SMasahisa Kojima } 562b0823ee3SMasahisa Kojima 563b0823ee3SMasahisa Kojima static irqreturn_t sq_spi_rx_handler(int irq, void *priv) 564b0823ee3SMasahisa Kojima { 565b0823ee3SMasahisa Kojima uint32_t val; 566b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = priv; 567b0823ee3SMasahisa Kojima 568b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_RXF); 569b0823ee3SMasahisa Kojima if ((val & SYNQUACER_HSSPI_RXF_SLAVE_RELEASED) || 570b0823ee3SMasahisa Kojima (val & SYNQUACER_HSSPI_RXF_FIFO_MORE_THAN_THRESHOLD)) { 571b0823ee3SMasahisa Kojima read_fifo(sspi); 572b0823ee3SMasahisa Kojima 573b0823ee3SMasahisa Kojima if (sspi->rx_words == 0) { 574b0823ee3SMasahisa Kojima writel(0, sspi->regs + SYNQUACER_HSSPI_REG_RXE); 575b0823ee3SMasahisa Kojima complete(&sspi->transfer_done); 576b0823ee3SMasahisa Kojima } 577b0823ee3SMasahisa Kojima return IRQ_HANDLED; 578b0823ee3SMasahisa Kojima } 579b0823ee3SMasahisa Kojima 580b0823ee3SMasahisa Kojima return IRQ_NONE; 581b0823ee3SMasahisa Kojima } 582b0823ee3SMasahisa Kojima 583b0823ee3SMasahisa Kojima static irqreturn_t sq_spi_tx_handler(int irq, void *priv) 584b0823ee3SMasahisa Kojima { 585b0823ee3SMasahisa Kojima uint32_t val; 586b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = priv; 587b0823ee3SMasahisa Kojima 588b0823ee3SMasahisa Kojima val = readl(sspi->regs + SYNQUACER_HSSPI_REG_TXF); 589b0823ee3SMasahisa Kojima if (val & SYNQUACER_HSSPI_TXF_FIFO_EMPTY) { 590b0823ee3SMasahisa Kojima if (sspi->tx_words == 0) { 591b0823ee3SMasahisa Kojima writel(0, sspi->regs + SYNQUACER_HSSPI_REG_TXE); 592b0823ee3SMasahisa Kojima complete(&sspi->transfer_done); 593b0823ee3SMasahisa Kojima } else { 594b0823ee3SMasahisa Kojima write_fifo(sspi); 595b0823ee3SMasahisa Kojima } 596b0823ee3SMasahisa Kojima return IRQ_HANDLED; 597b0823ee3SMasahisa Kojima } 598b0823ee3SMasahisa Kojima 599b0823ee3SMasahisa Kojima return IRQ_NONE; 600b0823ee3SMasahisa Kojima } 601b0823ee3SMasahisa Kojima 602b0823ee3SMasahisa Kojima static int synquacer_spi_probe(struct platform_device *pdev) 603b0823ee3SMasahisa Kojima { 604b0823ee3SMasahisa Kojima struct device_node *np = pdev->dev.of_node; 605b0823ee3SMasahisa Kojima struct spi_master *master; 606b0823ee3SMasahisa Kojima struct synquacer_spi *sspi; 607b0823ee3SMasahisa Kojima int ret; 608b0823ee3SMasahisa Kojima int rx_irq, tx_irq; 609b0823ee3SMasahisa Kojima 610b0823ee3SMasahisa Kojima master = spi_alloc_master(&pdev->dev, sizeof(*sspi)); 611b0823ee3SMasahisa Kojima if (!master) 612b0823ee3SMasahisa Kojima return -ENOMEM; 613b0823ee3SMasahisa Kojima 614b0823ee3SMasahisa Kojima platform_set_drvdata(pdev, master); 615b0823ee3SMasahisa Kojima 616b0823ee3SMasahisa Kojima sspi = spi_master_get_devdata(master); 617b0823ee3SMasahisa Kojima sspi->dev = &pdev->dev; 618b0823ee3SMasahisa Kojima 619b0823ee3SMasahisa Kojima init_completion(&sspi->transfer_done); 620b0823ee3SMasahisa Kojima 621b0823ee3SMasahisa Kojima sspi->regs = devm_platform_ioremap_resource(pdev, 0); 622b0823ee3SMasahisa Kojima if (IS_ERR(sspi->regs)) { 623b0823ee3SMasahisa Kojima ret = PTR_ERR(sspi->regs); 624b0823ee3SMasahisa Kojima goto put_spi; 625b0823ee3SMasahisa Kojima } 626b0823ee3SMasahisa Kojima 627b0823ee3SMasahisa Kojima sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; /* Default */ 628b0823ee3SMasahisa Kojima device_property_read_u32(&pdev->dev, "socionext,ihclk-rate", 629b0823ee3SMasahisa Kojima &master->max_speed_hz); /* for ACPI */ 630b0823ee3SMasahisa Kojima 631b0823ee3SMasahisa Kojima if (dev_of_node(&pdev->dev)) { 632b0823ee3SMasahisa Kojima if (device_property_match_string(&pdev->dev, 633b0823ee3SMasahisa Kojima "clock-names", "iHCLK") >= 0) { 634b0823ee3SMasahisa Kojima sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IHCLK; 635b0823ee3SMasahisa Kojima sspi->clk = devm_clk_get(sspi->dev, "iHCLK"); 636b0823ee3SMasahisa Kojima } else if (device_property_match_string(&pdev->dev, 637b0823ee3SMasahisa Kojima "clock-names", "iPCLK") >= 0) { 638b0823ee3SMasahisa Kojima sspi->clk_src_type = SYNQUACER_HSSPI_CLOCK_SRC_IPCLK; 639b0823ee3SMasahisa Kojima sspi->clk = devm_clk_get(sspi->dev, "iPCLK"); 640b0823ee3SMasahisa Kojima } else { 641b0823ee3SMasahisa Kojima dev_err(&pdev->dev, "specified wrong clock source\n"); 642b0823ee3SMasahisa Kojima ret = -EINVAL; 643b0823ee3SMasahisa Kojima goto put_spi; 644b0823ee3SMasahisa Kojima } 645b0823ee3SMasahisa Kojima 646b0823ee3SMasahisa Kojima if (IS_ERR(sspi->clk)) { 64774ee6dc1SKrzysztof Kozlowski ret = dev_err_probe(&pdev->dev, PTR_ERR(sspi->clk), 64874ee6dc1SKrzysztof Kozlowski "clock not found\n"); 649b0823ee3SMasahisa Kojima goto put_spi; 650b0823ee3SMasahisa Kojima } 651b0823ee3SMasahisa Kojima 652b0823ee3SMasahisa Kojima ret = clk_prepare_enable(sspi->clk); 653b0823ee3SMasahisa Kojima if (ret) { 654b0823ee3SMasahisa Kojima dev_err(&pdev->dev, "failed to enable clock (%d)\n", 655b0823ee3SMasahisa Kojima ret); 656b0823ee3SMasahisa Kojima goto put_spi; 657b0823ee3SMasahisa Kojima } 658b0823ee3SMasahisa Kojima 659b0823ee3SMasahisa Kojima master->max_speed_hz = clk_get_rate(sspi->clk); 660b0823ee3SMasahisa Kojima } 661b0823ee3SMasahisa Kojima 662b0823ee3SMasahisa Kojima if (!master->max_speed_hz) { 663b0823ee3SMasahisa Kojima dev_err(&pdev->dev, "missing clock source\n"); 6648853b250SLukas Wunner ret = -EINVAL; 6658853b250SLukas Wunner goto disable_clk; 666b0823ee3SMasahisa Kojima } 667b0823ee3SMasahisa Kojima master->min_speed_hz = master->max_speed_hz / 254; 668b0823ee3SMasahisa Kojima 669b0823ee3SMasahisa Kojima sspi->aces = device_property_read_bool(&pdev->dev, 670b0823ee3SMasahisa Kojima "socionext,set-aces"); 671b0823ee3SMasahisa Kojima sspi->rtm = device_property_read_bool(&pdev->dev, "socionext,use-rtm"); 672b0823ee3SMasahisa Kojima 673b0823ee3SMasahisa Kojima master->num_chipselect = SYNQUACER_HSSPI_NUM_CHIP_SELECT; 674b0823ee3SMasahisa Kojima 675b0823ee3SMasahisa Kojima rx_irq = platform_get_irq(pdev, 0); 676b0823ee3SMasahisa Kojima if (rx_irq <= 0) { 677b0823ee3SMasahisa Kojima ret = rx_irq; 6788853b250SLukas Wunner goto disable_clk; 679b0823ee3SMasahisa Kojima } 680b0823ee3SMasahisa Kojima snprintf(sspi->rx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-rx", 681b0823ee3SMasahisa Kojima dev_name(&pdev->dev)); 682b0823ee3SMasahisa Kojima ret = devm_request_irq(&pdev->dev, rx_irq, sq_spi_rx_handler, 683b0823ee3SMasahisa Kojima 0, sspi->rx_irq_name, sspi); 684b0823ee3SMasahisa Kojima if (ret) { 685b0823ee3SMasahisa Kojima dev_err(&pdev->dev, "request rx_irq failed (%d)\n", ret); 6868853b250SLukas Wunner goto disable_clk; 687b0823ee3SMasahisa Kojima } 688b0823ee3SMasahisa Kojima 689b0823ee3SMasahisa Kojima tx_irq = platform_get_irq(pdev, 1); 690b0823ee3SMasahisa Kojima if (tx_irq <= 0) { 691b0823ee3SMasahisa Kojima ret = tx_irq; 6928853b250SLukas Wunner goto disable_clk; 693b0823ee3SMasahisa Kojima } 694b0823ee3SMasahisa Kojima snprintf(sspi->tx_irq_name, SYNQUACER_HSSPI_IRQ_NAME_MAX, "%s-tx", 695b0823ee3SMasahisa Kojima dev_name(&pdev->dev)); 696b0823ee3SMasahisa Kojima ret = devm_request_irq(&pdev->dev, tx_irq, sq_spi_tx_handler, 697b0823ee3SMasahisa Kojima 0, sspi->tx_irq_name, sspi); 698b0823ee3SMasahisa Kojima if (ret) { 699b0823ee3SMasahisa Kojima dev_err(&pdev->dev, "request tx_irq failed (%d)\n", ret); 7008853b250SLukas Wunner goto disable_clk; 701b0823ee3SMasahisa Kojima } 702b0823ee3SMasahisa Kojima 703b0823ee3SMasahisa Kojima master->dev.of_node = np; 704b0823ee3SMasahisa Kojima master->dev.fwnode = pdev->dev.fwnode; 705b0823ee3SMasahisa Kojima master->auto_runtime_pm = true; 706b0823ee3SMasahisa Kojima master->bus_num = pdev->id; 707b0823ee3SMasahisa Kojima 708b0823ee3SMasahisa Kojima master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL | 709b0823ee3SMasahisa Kojima SPI_TX_QUAD | SPI_RX_QUAD; 710b0823ee3SMasahisa Kojima master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(24) | 711b0823ee3SMasahisa Kojima SPI_BPW_MASK(16) | SPI_BPW_MASK(8); 712b0823ee3SMasahisa Kojima 713b0823ee3SMasahisa Kojima master->set_cs = synquacer_spi_set_cs; 714b0823ee3SMasahisa Kojima master->transfer_one = synquacer_spi_transfer_one; 715b0823ee3SMasahisa Kojima 716b0823ee3SMasahisa Kojima ret = synquacer_spi_enable(master); 717b0823ee3SMasahisa Kojima if (ret) 7188853b250SLukas Wunner goto disable_clk; 719b0823ee3SMasahisa Kojima 720b0823ee3SMasahisa Kojima pm_runtime_set_active(sspi->dev); 721b0823ee3SMasahisa Kojima pm_runtime_enable(sspi->dev); 722b0823ee3SMasahisa Kojima 723b0823ee3SMasahisa Kojima ret = devm_spi_register_master(sspi->dev, master); 724b0823ee3SMasahisa Kojima if (ret) 725b0823ee3SMasahisa Kojima goto disable_pm; 726b0823ee3SMasahisa Kojima 727b0823ee3SMasahisa Kojima return 0; 728b0823ee3SMasahisa Kojima 729b0823ee3SMasahisa Kojima disable_pm: 730b0823ee3SMasahisa Kojima pm_runtime_disable(sspi->dev); 7318853b250SLukas Wunner disable_clk: 732b0823ee3SMasahisa Kojima clk_disable_unprepare(sspi->clk); 733b0823ee3SMasahisa Kojima put_spi: 734b0823ee3SMasahisa Kojima spi_master_put(master); 735b0823ee3SMasahisa Kojima 736b0823ee3SMasahisa Kojima return ret; 737b0823ee3SMasahisa Kojima } 738b0823ee3SMasahisa Kojima 739b0823ee3SMasahisa Kojima static int synquacer_spi_remove(struct platform_device *pdev) 740b0823ee3SMasahisa Kojima { 741b0823ee3SMasahisa Kojima struct spi_master *master = platform_get_drvdata(pdev); 742b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = spi_master_get_devdata(master); 743b0823ee3SMasahisa Kojima 744b0823ee3SMasahisa Kojima pm_runtime_disable(sspi->dev); 745b0823ee3SMasahisa Kojima 746b0823ee3SMasahisa Kojima clk_disable_unprepare(sspi->clk); 747b0823ee3SMasahisa Kojima 748b0823ee3SMasahisa Kojima return 0; 749b0823ee3SMasahisa Kojima } 750b0823ee3SMasahisa Kojima 751b0823ee3SMasahisa Kojima static int __maybe_unused synquacer_spi_suspend(struct device *dev) 752b0823ee3SMasahisa Kojima { 753b0823ee3SMasahisa Kojima struct spi_master *master = dev_get_drvdata(dev); 754b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = spi_master_get_devdata(master); 755b0823ee3SMasahisa Kojima int ret; 756b0823ee3SMasahisa Kojima 757b0823ee3SMasahisa Kojima ret = spi_master_suspend(master); 758b0823ee3SMasahisa Kojima if (ret) 759b0823ee3SMasahisa Kojima return ret; 760b0823ee3SMasahisa Kojima 761b0823ee3SMasahisa Kojima if (!pm_runtime_suspended(dev)) 762b0823ee3SMasahisa Kojima clk_disable_unprepare(sspi->clk); 763b0823ee3SMasahisa Kojima 764b0823ee3SMasahisa Kojima return ret; 765b0823ee3SMasahisa Kojima } 766b0823ee3SMasahisa Kojima 767b0823ee3SMasahisa Kojima static int __maybe_unused synquacer_spi_resume(struct device *dev) 768b0823ee3SMasahisa Kojima { 769b0823ee3SMasahisa Kojima struct spi_master *master = dev_get_drvdata(dev); 770b0823ee3SMasahisa Kojima struct synquacer_spi *sspi = spi_master_get_devdata(master); 771b0823ee3SMasahisa Kojima int ret; 772b0823ee3SMasahisa Kojima 773b0823ee3SMasahisa Kojima if (!pm_runtime_suspended(dev)) { 774b0823ee3SMasahisa Kojima /* Ensure reconfigure during next xfer */ 775b0823ee3SMasahisa Kojima sspi->speed = 0; 776b0823ee3SMasahisa Kojima 777b0823ee3SMasahisa Kojima ret = clk_prepare_enable(sspi->clk); 778b0823ee3SMasahisa Kojima if (ret < 0) { 779b0823ee3SMasahisa Kojima dev_err(dev, "failed to enable clk (%d)\n", 780b0823ee3SMasahisa Kojima ret); 781b0823ee3SMasahisa Kojima return ret; 782b0823ee3SMasahisa Kojima } 783b0823ee3SMasahisa Kojima 784b0823ee3SMasahisa Kojima ret = synquacer_spi_enable(master); 785b0823ee3SMasahisa Kojima if (ret) { 786*917e43deSGuo Mengqi clk_disable_unprepare(sspi->clk); 787b0823ee3SMasahisa Kojima dev_err(dev, "failed to enable spi (%d)\n", ret); 788b0823ee3SMasahisa Kojima return ret; 789b0823ee3SMasahisa Kojima } 790b0823ee3SMasahisa Kojima } 791b0823ee3SMasahisa Kojima 792b0823ee3SMasahisa Kojima ret = spi_master_resume(master); 793b0823ee3SMasahisa Kojima if (ret < 0) 794b0823ee3SMasahisa Kojima clk_disable_unprepare(sspi->clk); 795b0823ee3SMasahisa Kojima 796b0823ee3SMasahisa Kojima return ret; 797b0823ee3SMasahisa Kojima } 798b0823ee3SMasahisa Kojima 799b0823ee3SMasahisa Kojima static SIMPLE_DEV_PM_OPS(synquacer_spi_pm_ops, synquacer_spi_suspend, 800b0823ee3SMasahisa Kojima synquacer_spi_resume); 801b0823ee3SMasahisa Kojima 802b0823ee3SMasahisa Kojima static const struct of_device_id synquacer_spi_of_match[] = { 803b0823ee3SMasahisa Kojima {.compatible = "socionext,synquacer-spi"}, 804b0823ee3SMasahisa Kojima {} 805b0823ee3SMasahisa Kojima }; 806b0823ee3SMasahisa Kojima MODULE_DEVICE_TABLE(of, synquacer_spi_of_match); 807b0823ee3SMasahisa Kojima 808b0823ee3SMasahisa Kojima #ifdef CONFIG_ACPI 809b0823ee3SMasahisa Kojima static const struct acpi_device_id synquacer_hsspi_acpi_ids[] = { 810b0823ee3SMasahisa Kojima { "SCX0004" }, 811b0823ee3SMasahisa Kojima { /* sentinel */ } 812b0823ee3SMasahisa Kojima }; 813b0823ee3SMasahisa Kojima MODULE_DEVICE_TABLE(acpi, synquacer_hsspi_acpi_ids); 814b0823ee3SMasahisa Kojima #endif 815b0823ee3SMasahisa Kojima 816b0823ee3SMasahisa Kojima static struct platform_driver synquacer_spi_driver = { 817b0823ee3SMasahisa Kojima .driver = { 818b0823ee3SMasahisa Kojima .name = "synquacer-spi", 819b0823ee3SMasahisa Kojima .pm = &synquacer_spi_pm_ops, 820b0823ee3SMasahisa Kojima .of_match_table = synquacer_spi_of_match, 821b0823ee3SMasahisa Kojima .acpi_match_table = ACPI_PTR(synquacer_hsspi_acpi_ids), 822b0823ee3SMasahisa Kojima }, 823b0823ee3SMasahisa Kojima .probe = synquacer_spi_probe, 824b0823ee3SMasahisa Kojima .remove = synquacer_spi_remove, 825b0823ee3SMasahisa Kojima }; 826b0823ee3SMasahisa Kojima module_platform_driver(synquacer_spi_driver); 827b0823ee3SMasahisa Kojima 828b0823ee3SMasahisa Kojima MODULE_DESCRIPTION("Socionext Synquacer HS-SPI controller driver"); 829b0823ee3SMasahisa Kojima MODULE_AUTHOR("Masahisa Kojima <masahisa.kojima@linaro.org>"); 830b0823ee3SMasahisa Kojima MODULE_AUTHOR("Jassi Brar <jaswinder.singh@linaro.org>"); 831b0823ee3SMasahisa Kojima MODULE_LICENSE("GPL v2"); 832