18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Freescale eSPI controller driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2010 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/err.h> 98c2ecf20Sopenharmony_ci#include <linux/fsl_devices.h> 108c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/mm.h> 138c2ecf20Sopenharmony_ci#include <linux/of.h> 148c2ecf20Sopenharmony_ci#include <linux/of_address.h> 158c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 168c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 198c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 208c2ecf20Sopenharmony_ci#include <sysdev/fsl_soc.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* eSPI Controller registers */ 238c2ecf20Sopenharmony_ci#define ESPI_SPMODE 0x00 /* eSPI mode register */ 248c2ecf20Sopenharmony_ci#define ESPI_SPIE 0x04 /* eSPI event register */ 258c2ecf20Sopenharmony_ci#define ESPI_SPIM 0x08 /* eSPI mask register */ 268c2ecf20Sopenharmony_ci#define ESPI_SPCOM 0x0c /* eSPI command register */ 278c2ecf20Sopenharmony_ci#define ESPI_SPITF 0x10 /* eSPI transmit FIFO access register*/ 288c2ecf20Sopenharmony_ci#define ESPI_SPIRF 0x14 /* eSPI receive FIFO access register*/ 298c2ecf20Sopenharmony_ci#define ESPI_SPMODE0 0x20 /* eSPI cs0 mode register */ 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define ESPI_SPMODEx(x) (ESPI_SPMODE0 + (x) * 4) 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* eSPI Controller mode register definitions */ 348c2ecf20Sopenharmony_ci#define SPMODE_ENABLE BIT(31) 358c2ecf20Sopenharmony_ci#define SPMODE_LOOP BIT(30) 368c2ecf20Sopenharmony_ci#define SPMODE_TXTHR(x) ((x) << 8) 378c2ecf20Sopenharmony_ci#define SPMODE_RXTHR(x) ((x) << 0) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* eSPI Controller CS mode register definitions */ 408c2ecf20Sopenharmony_ci#define CSMODE_CI_INACTIVEHIGH BIT(31) 418c2ecf20Sopenharmony_ci#define CSMODE_CP_BEGIN_EDGECLK BIT(30) 428c2ecf20Sopenharmony_ci#define CSMODE_REV BIT(29) 438c2ecf20Sopenharmony_ci#define CSMODE_DIV16 BIT(28) 448c2ecf20Sopenharmony_ci#define CSMODE_PM(x) ((x) << 24) 458c2ecf20Sopenharmony_ci#define CSMODE_POL_1 BIT(20) 468c2ecf20Sopenharmony_ci#define CSMODE_LEN(x) ((x) << 16) 478c2ecf20Sopenharmony_ci#define CSMODE_BEF(x) ((x) << 12) 488c2ecf20Sopenharmony_ci#define CSMODE_AFT(x) ((x) << 8) 498c2ecf20Sopenharmony_ci#define CSMODE_CG(x) ((x) << 3) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define FSL_ESPI_FIFO_SIZE 32 528c2ecf20Sopenharmony_ci#define FSL_ESPI_RXTHR 15 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Default mode/csmode for eSPI controller */ 558c2ecf20Sopenharmony_ci#define SPMODE_INIT_VAL (SPMODE_TXTHR(4) | SPMODE_RXTHR(FSL_ESPI_RXTHR)) 568c2ecf20Sopenharmony_ci#define CSMODE_INIT_VAL (CSMODE_POL_1 | CSMODE_BEF(0) \ 578c2ecf20Sopenharmony_ci | CSMODE_AFT(0) | CSMODE_CG(1)) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* SPIE register values */ 608c2ecf20Sopenharmony_ci#define SPIE_RXCNT(reg) ((reg >> 24) & 0x3F) 618c2ecf20Sopenharmony_ci#define SPIE_TXCNT(reg) ((reg >> 16) & 0x3F) 628c2ecf20Sopenharmony_ci#define SPIE_TXE BIT(15) /* TX FIFO empty */ 638c2ecf20Sopenharmony_ci#define SPIE_DON BIT(14) /* TX done */ 648c2ecf20Sopenharmony_ci#define SPIE_RXT BIT(13) /* RX FIFO threshold */ 658c2ecf20Sopenharmony_ci#define SPIE_RXF BIT(12) /* RX FIFO full */ 668c2ecf20Sopenharmony_ci#define SPIE_TXT BIT(11) /* TX FIFO threshold*/ 678c2ecf20Sopenharmony_ci#define SPIE_RNE BIT(9) /* RX FIFO not empty */ 688c2ecf20Sopenharmony_ci#define SPIE_TNF BIT(8) /* TX FIFO not full */ 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* SPIM register values */ 718c2ecf20Sopenharmony_ci#define SPIM_TXE BIT(15) /* TX FIFO empty */ 728c2ecf20Sopenharmony_ci#define SPIM_DON BIT(14) /* TX done */ 738c2ecf20Sopenharmony_ci#define SPIM_RXT BIT(13) /* RX FIFO threshold */ 748c2ecf20Sopenharmony_ci#define SPIM_RXF BIT(12) /* RX FIFO full */ 758c2ecf20Sopenharmony_ci#define SPIM_TXT BIT(11) /* TX FIFO threshold*/ 768c2ecf20Sopenharmony_ci#define SPIM_RNE BIT(9) /* RX FIFO not empty */ 778c2ecf20Sopenharmony_ci#define SPIM_TNF BIT(8) /* TX FIFO not full */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* SPCOM register values */ 808c2ecf20Sopenharmony_ci#define SPCOM_CS(x) ((x) << 30) 818c2ecf20Sopenharmony_ci#define SPCOM_DO BIT(28) /* Dual output */ 828c2ecf20Sopenharmony_ci#define SPCOM_TO BIT(27) /* TX only */ 838c2ecf20Sopenharmony_ci#define SPCOM_RXSKIP(x) ((x) << 16) 848c2ecf20Sopenharmony_ci#define SPCOM_TRANLEN(x) ((x) << 0) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#define SPCOM_TRANLEN_MAX 0x10000 /* Max transaction length */ 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define AUTOSUSPEND_TIMEOUT 2000 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct fsl_espi { 918c2ecf20Sopenharmony_ci struct device *dev; 928c2ecf20Sopenharmony_ci void __iomem *reg_base; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci struct list_head *m_transfers; 958c2ecf20Sopenharmony_ci struct spi_transfer *tx_t; 968c2ecf20Sopenharmony_ci unsigned int tx_pos; 978c2ecf20Sopenharmony_ci bool tx_done; 988c2ecf20Sopenharmony_ci struct spi_transfer *rx_t; 998c2ecf20Sopenharmony_ci unsigned int rx_pos; 1008c2ecf20Sopenharmony_ci bool rx_done; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci bool swab; 1038c2ecf20Sopenharmony_ci unsigned int rxskip; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci spinlock_t lock; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci u32 spibrg; /* SPIBRG input clock */ 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci struct completion done; 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistruct fsl_espi_cs { 1138c2ecf20Sopenharmony_ci u32 hw_mode; 1148c2ecf20Sopenharmony_ci}; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic inline u32 fsl_espi_read_reg(struct fsl_espi *espi, int offset) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return ioread32be(espi->reg_base + offset); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic inline u16 fsl_espi_read_reg16(struct fsl_espi *espi, int offset) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci return ioread16be(espi->reg_base + offset); 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic inline u8 fsl_espi_read_reg8(struct fsl_espi *espi, int offset) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci return ioread8(espi->reg_base + offset); 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline void fsl_espi_write_reg(struct fsl_espi *espi, int offset, 1328c2ecf20Sopenharmony_ci u32 val) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci iowrite32be(val, espi->reg_base + offset); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic inline void fsl_espi_write_reg16(struct fsl_espi *espi, int offset, 1388c2ecf20Sopenharmony_ci u16 val) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci iowrite16be(val, espi->reg_base + offset); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic inline void fsl_espi_write_reg8(struct fsl_espi *espi, int offset, 1448c2ecf20Sopenharmony_ci u8 val) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci iowrite8(val, espi->reg_base + offset); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int fsl_espi_check_message(struct spi_message *m) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct fsl_espi *espi = spi_master_get_devdata(m->spi->master); 1528c2ecf20Sopenharmony_ci struct spi_transfer *t, *first; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (m->frame_length > SPCOM_TRANLEN_MAX) { 1558c2ecf20Sopenharmony_ci dev_err(espi->dev, "message too long, size is %u bytes\n", 1568c2ecf20Sopenharmony_ci m->frame_length); 1578c2ecf20Sopenharmony_ci return -EMSGSIZE; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci first = list_first_entry(&m->transfers, struct spi_transfer, 1618c2ecf20Sopenharmony_ci transfer_list); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci list_for_each_entry(t, &m->transfers, transfer_list) { 1648c2ecf20Sopenharmony_ci if (first->bits_per_word != t->bits_per_word || 1658c2ecf20Sopenharmony_ci first->speed_hz != t->speed_hz) { 1668c2ecf20Sopenharmony_ci dev_err(espi->dev, "bits_per_word/speed_hz should be the same for all transfers\n"); 1678c2ecf20Sopenharmony_ci return -EINVAL; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci /* ESPI supports MSB-first transfers for word size 8 / 16 only */ 1728c2ecf20Sopenharmony_ci if (!(m->spi->mode & SPI_LSB_FIRST) && first->bits_per_word != 8 && 1738c2ecf20Sopenharmony_ci first->bits_per_word != 16) { 1748c2ecf20Sopenharmony_ci dev_err(espi->dev, 1758c2ecf20Sopenharmony_ci "MSB-first transfer not supported for wordsize %u\n", 1768c2ecf20Sopenharmony_ci first->bits_per_word); 1778c2ecf20Sopenharmony_ci return -EINVAL; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic unsigned int fsl_espi_check_rxskip_mode(struct spi_message *m) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct spi_transfer *t; 1868c2ecf20Sopenharmony_ci unsigned int i = 0, rxskip = 0; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * prerequisites for ESPI rxskip mode: 1908c2ecf20Sopenharmony_ci * - message has two transfers 1918c2ecf20Sopenharmony_ci * - first transfer is a write and second is a read 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * In addition the current low-level transfer mechanism requires 1948c2ecf20Sopenharmony_ci * that the rxskip bytes fit into the TX FIFO. Else the transfer 1958c2ecf20Sopenharmony_ci * would hang because after the first FSL_ESPI_FIFO_SIZE bytes 1968c2ecf20Sopenharmony_ci * the TX FIFO isn't re-filled. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci list_for_each_entry(t, &m->transfers, transfer_list) { 1998c2ecf20Sopenharmony_ci if (i == 0) { 2008c2ecf20Sopenharmony_ci if (!t->tx_buf || t->rx_buf || 2018c2ecf20Sopenharmony_ci t->len > FSL_ESPI_FIFO_SIZE) 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci rxskip = t->len; 2048c2ecf20Sopenharmony_ci } else if (i == 1) { 2058c2ecf20Sopenharmony_ci if (t->tx_buf || !t->rx_buf) 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci i++; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci return i == 2 ? rxskip : 0; 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic void fsl_espi_fill_tx_fifo(struct fsl_espi *espi, u32 events) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u32 tx_fifo_avail; 2178c2ecf20Sopenharmony_ci unsigned int tx_left; 2188c2ecf20Sopenharmony_ci const void *tx_buf; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* if events is zero transfer has not started and tx fifo is empty */ 2218c2ecf20Sopenharmony_ci tx_fifo_avail = events ? SPIE_TXCNT(events) : FSL_ESPI_FIFO_SIZE; 2228c2ecf20Sopenharmony_cistart: 2238c2ecf20Sopenharmony_ci tx_left = espi->tx_t->len - espi->tx_pos; 2248c2ecf20Sopenharmony_ci tx_buf = espi->tx_t->tx_buf; 2258c2ecf20Sopenharmony_ci while (tx_fifo_avail >= min(4U, tx_left) && tx_left) { 2268c2ecf20Sopenharmony_ci if (tx_left >= 4) { 2278c2ecf20Sopenharmony_ci if (!tx_buf) 2288c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPITF, 0); 2298c2ecf20Sopenharmony_ci else if (espi->swab) 2308c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPITF, 2318c2ecf20Sopenharmony_ci swahb32p(tx_buf + espi->tx_pos)); 2328c2ecf20Sopenharmony_ci else 2338c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPITF, 2348c2ecf20Sopenharmony_ci *(u32 *)(tx_buf + espi->tx_pos)); 2358c2ecf20Sopenharmony_ci espi->tx_pos += 4; 2368c2ecf20Sopenharmony_ci tx_left -= 4; 2378c2ecf20Sopenharmony_ci tx_fifo_avail -= 4; 2388c2ecf20Sopenharmony_ci } else if (tx_left >= 2 && tx_buf && espi->swab) { 2398c2ecf20Sopenharmony_ci fsl_espi_write_reg16(espi, ESPI_SPITF, 2408c2ecf20Sopenharmony_ci swab16p(tx_buf + espi->tx_pos)); 2418c2ecf20Sopenharmony_ci espi->tx_pos += 2; 2428c2ecf20Sopenharmony_ci tx_left -= 2; 2438c2ecf20Sopenharmony_ci tx_fifo_avail -= 2; 2448c2ecf20Sopenharmony_ci } else { 2458c2ecf20Sopenharmony_ci if (!tx_buf) 2468c2ecf20Sopenharmony_ci fsl_espi_write_reg8(espi, ESPI_SPITF, 0); 2478c2ecf20Sopenharmony_ci else 2488c2ecf20Sopenharmony_ci fsl_espi_write_reg8(espi, ESPI_SPITF, 2498c2ecf20Sopenharmony_ci *(u8 *)(tx_buf + espi->tx_pos)); 2508c2ecf20Sopenharmony_ci espi->tx_pos += 1; 2518c2ecf20Sopenharmony_ci tx_left -= 1; 2528c2ecf20Sopenharmony_ci tx_fifo_avail -= 1; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!tx_left) { 2578c2ecf20Sopenharmony_ci /* Last transfer finished, in rxskip mode only one is needed */ 2588c2ecf20Sopenharmony_ci if (list_is_last(&espi->tx_t->transfer_list, 2598c2ecf20Sopenharmony_ci espi->m_transfers) || espi->rxskip) { 2608c2ecf20Sopenharmony_ci espi->tx_done = true; 2618c2ecf20Sopenharmony_ci return; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci espi->tx_t = list_next_entry(espi->tx_t, transfer_list); 2648c2ecf20Sopenharmony_ci espi->tx_pos = 0; 2658c2ecf20Sopenharmony_ci /* continue with next transfer if tx fifo is not full */ 2668c2ecf20Sopenharmony_ci if (tx_fifo_avail) 2678c2ecf20Sopenharmony_ci goto start; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic void fsl_espi_read_rx_fifo(struct fsl_espi *espi, u32 events) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci u32 rx_fifo_avail = SPIE_RXCNT(events); 2748c2ecf20Sopenharmony_ci unsigned int rx_left; 2758c2ecf20Sopenharmony_ci void *rx_buf; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistart: 2788c2ecf20Sopenharmony_ci rx_left = espi->rx_t->len - espi->rx_pos; 2798c2ecf20Sopenharmony_ci rx_buf = espi->rx_t->rx_buf; 2808c2ecf20Sopenharmony_ci while (rx_fifo_avail >= min(4U, rx_left) && rx_left) { 2818c2ecf20Sopenharmony_ci if (rx_left >= 4) { 2828c2ecf20Sopenharmony_ci u32 val = fsl_espi_read_reg(espi, ESPI_SPIRF); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (rx_buf && espi->swab) 2858c2ecf20Sopenharmony_ci *(u32 *)(rx_buf + espi->rx_pos) = swahb32(val); 2868c2ecf20Sopenharmony_ci else if (rx_buf) 2878c2ecf20Sopenharmony_ci *(u32 *)(rx_buf + espi->rx_pos) = val; 2888c2ecf20Sopenharmony_ci espi->rx_pos += 4; 2898c2ecf20Sopenharmony_ci rx_left -= 4; 2908c2ecf20Sopenharmony_ci rx_fifo_avail -= 4; 2918c2ecf20Sopenharmony_ci } else if (rx_left >= 2 && rx_buf && espi->swab) { 2928c2ecf20Sopenharmony_ci u16 val = fsl_espi_read_reg16(espi, ESPI_SPIRF); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci *(u16 *)(rx_buf + espi->rx_pos) = swab16(val); 2958c2ecf20Sopenharmony_ci espi->rx_pos += 2; 2968c2ecf20Sopenharmony_ci rx_left -= 2; 2978c2ecf20Sopenharmony_ci rx_fifo_avail -= 2; 2988c2ecf20Sopenharmony_ci } else { 2998c2ecf20Sopenharmony_ci u8 val = fsl_espi_read_reg8(espi, ESPI_SPIRF); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (rx_buf) 3028c2ecf20Sopenharmony_ci *(u8 *)(rx_buf + espi->rx_pos) = val; 3038c2ecf20Sopenharmony_ci espi->rx_pos += 1; 3048c2ecf20Sopenharmony_ci rx_left -= 1; 3058c2ecf20Sopenharmony_ci rx_fifo_avail -= 1; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci if (!rx_left) { 3108c2ecf20Sopenharmony_ci if (list_is_last(&espi->rx_t->transfer_list, 3118c2ecf20Sopenharmony_ci espi->m_transfers)) { 3128c2ecf20Sopenharmony_ci espi->rx_done = true; 3138c2ecf20Sopenharmony_ci return; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci espi->rx_t = list_next_entry(espi->rx_t, transfer_list); 3168c2ecf20Sopenharmony_ci espi->rx_pos = 0; 3178c2ecf20Sopenharmony_ci /* continue with next transfer if rx fifo is not empty */ 3188c2ecf20Sopenharmony_ci if (rx_fifo_avail) 3198c2ecf20Sopenharmony_ci goto start; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic void fsl_espi_setup_transfer(struct spi_device *spi, 3248c2ecf20Sopenharmony_ci struct spi_transfer *t) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct fsl_espi *espi = spi_master_get_devdata(spi->master); 3278c2ecf20Sopenharmony_ci int bits_per_word = t ? t->bits_per_word : spi->bits_per_word; 3288c2ecf20Sopenharmony_ci u32 pm, hz = t ? t->speed_hz : spi->max_speed_hz; 3298c2ecf20Sopenharmony_ci struct fsl_espi_cs *cs = spi_get_ctldata(spi); 3308c2ecf20Sopenharmony_ci u32 hw_mode_old = cs->hw_mode; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* mask out bits we are going to set */ 3338c2ecf20Sopenharmony_ci cs->hw_mode &= ~(CSMODE_LEN(0xF) | CSMODE_DIV16 | CSMODE_PM(0xF)); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci cs->hw_mode |= CSMODE_LEN(bits_per_word - 1); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci pm = DIV_ROUND_UP(espi->spibrg, hz * 4) - 1; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci if (pm > 15) { 3408c2ecf20Sopenharmony_ci cs->hw_mode |= CSMODE_DIV16; 3418c2ecf20Sopenharmony_ci pm = DIV_ROUND_UP(espi->spibrg, hz * 16 * 4) - 1; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci cs->hw_mode |= CSMODE_PM(pm); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* don't write the mode register if the mode doesn't change */ 3478c2ecf20Sopenharmony_ci if (cs->hw_mode != hw_mode_old) 3488c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPMODEx(spi->chip_select), 3498c2ecf20Sopenharmony_ci cs->hw_mode); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic int fsl_espi_bufs(struct spi_device *spi, struct spi_transfer *t) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct fsl_espi *espi = spi_master_get_devdata(spi->master); 3558c2ecf20Sopenharmony_ci unsigned int rx_len = t->len; 3568c2ecf20Sopenharmony_ci u32 mask, spcom; 3578c2ecf20Sopenharmony_ci int ret; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci reinit_completion(&espi->done); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Set SPCOM[CS] and SPCOM[TRANLEN] field */ 3628c2ecf20Sopenharmony_ci spcom = SPCOM_CS(spi->chip_select); 3638c2ecf20Sopenharmony_ci spcom |= SPCOM_TRANLEN(t->len - 1); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* configure RXSKIP mode */ 3668c2ecf20Sopenharmony_ci if (espi->rxskip) { 3678c2ecf20Sopenharmony_ci spcom |= SPCOM_RXSKIP(espi->rxskip); 3688c2ecf20Sopenharmony_ci rx_len = t->len - espi->rxskip; 3698c2ecf20Sopenharmony_ci if (t->rx_nbits == SPI_NBITS_DUAL) 3708c2ecf20Sopenharmony_ci spcom |= SPCOM_DO; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPCOM, spcom); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* enable interrupts */ 3768c2ecf20Sopenharmony_ci mask = SPIM_DON; 3778c2ecf20Sopenharmony_ci if (rx_len > FSL_ESPI_FIFO_SIZE) 3788c2ecf20Sopenharmony_ci mask |= SPIM_RXT; 3798c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPIM, mask); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* Prevent filling the fifo from getting interrupted */ 3828c2ecf20Sopenharmony_ci spin_lock_irq(&espi->lock); 3838c2ecf20Sopenharmony_ci fsl_espi_fill_tx_fifo(espi, 0); 3848c2ecf20Sopenharmony_ci spin_unlock_irq(&espi->lock); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Won't hang up forever, SPI bus sometimes got lost interrupts... */ 3878c2ecf20Sopenharmony_ci ret = wait_for_completion_timeout(&espi->done, 2 * HZ); 3888c2ecf20Sopenharmony_ci if (ret == 0) 3898c2ecf20Sopenharmony_ci dev_err(espi->dev, "Transfer timed out!\n"); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* disable rx ints */ 3928c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPIM, 0); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return ret == 0 ? -ETIMEDOUT : 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic int fsl_espi_trans(struct spi_message *m, struct spi_transfer *trans) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct fsl_espi *espi = spi_master_get_devdata(m->spi->master); 4008c2ecf20Sopenharmony_ci struct spi_device *spi = m->spi; 4018c2ecf20Sopenharmony_ci int ret; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* In case of LSB-first and bits_per_word > 8 byte-swap all words */ 4048c2ecf20Sopenharmony_ci espi->swab = spi->mode & SPI_LSB_FIRST && trans->bits_per_word > 8; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci espi->m_transfers = &m->transfers; 4078c2ecf20Sopenharmony_ci espi->tx_t = list_first_entry(&m->transfers, struct spi_transfer, 4088c2ecf20Sopenharmony_ci transfer_list); 4098c2ecf20Sopenharmony_ci espi->tx_pos = 0; 4108c2ecf20Sopenharmony_ci espi->tx_done = false; 4118c2ecf20Sopenharmony_ci espi->rx_t = list_first_entry(&m->transfers, struct spi_transfer, 4128c2ecf20Sopenharmony_ci transfer_list); 4138c2ecf20Sopenharmony_ci espi->rx_pos = 0; 4148c2ecf20Sopenharmony_ci espi->rx_done = false; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci espi->rxskip = fsl_espi_check_rxskip_mode(m); 4178c2ecf20Sopenharmony_ci if (trans->rx_nbits == SPI_NBITS_DUAL && !espi->rxskip) { 4188c2ecf20Sopenharmony_ci dev_err(espi->dev, "Dual output mode requires RXSKIP mode!\n"); 4198c2ecf20Sopenharmony_ci return -EINVAL; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* In RXSKIP mode skip first transfer for reads */ 4238c2ecf20Sopenharmony_ci if (espi->rxskip) 4248c2ecf20Sopenharmony_ci espi->rx_t = list_next_entry(espi->rx_t, transfer_list); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci fsl_espi_setup_transfer(spi, trans); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ret = fsl_espi_bufs(spi, trans); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci spi_transfer_delay_exec(trans); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return ret; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic int fsl_espi_do_one_msg(struct spi_master *master, 4368c2ecf20Sopenharmony_ci struct spi_message *m) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci unsigned int delay_usecs = 0, rx_nbits = 0; 4398c2ecf20Sopenharmony_ci unsigned int delay_nsecs = 0, delay_nsecs1 = 0; 4408c2ecf20Sopenharmony_ci struct spi_transfer *t, trans = {}; 4418c2ecf20Sopenharmony_ci int ret; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci ret = fsl_espi_check_message(m); 4448c2ecf20Sopenharmony_ci if (ret) 4458c2ecf20Sopenharmony_ci goto out; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci list_for_each_entry(t, &m->transfers, transfer_list) { 4488c2ecf20Sopenharmony_ci if (t->delay_usecs) { 4498c2ecf20Sopenharmony_ci if (t->delay_usecs > delay_usecs) { 4508c2ecf20Sopenharmony_ci delay_usecs = t->delay_usecs; 4518c2ecf20Sopenharmony_ci delay_nsecs = delay_usecs * 1000; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci } else { 4548c2ecf20Sopenharmony_ci delay_nsecs1 = spi_delay_to_ns(&t->delay, t); 4558c2ecf20Sopenharmony_ci if (delay_nsecs1 > delay_nsecs) 4568c2ecf20Sopenharmony_ci delay_nsecs = delay_nsecs1; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci if (t->rx_nbits > rx_nbits) 4598c2ecf20Sopenharmony_ci rx_nbits = t->rx_nbits; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci t = list_first_entry(&m->transfers, struct spi_transfer, 4638c2ecf20Sopenharmony_ci transfer_list); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci trans.len = m->frame_length; 4668c2ecf20Sopenharmony_ci trans.speed_hz = t->speed_hz; 4678c2ecf20Sopenharmony_ci trans.bits_per_word = t->bits_per_word; 4688c2ecf20Sopenharmony_ci trans.delay.value = delay_nsecs; 4698c2ecf20Sopenharmony_ci trans.delay.unit = SPI_DELAY_UNIT_NSECS; 4708c2ecf20Sopenharmony_ci trans.rx_nbits = rx_nbits; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (trans.len) 4738c2ecf20Sopenharmony_ci ret = fsl_espi_trans(m, &trans); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci m->actual_length = ret ? 0 : trans.len; 4768c2ecf20Sopenharmony_ciout: 4778c2ecf20Sopenharmony_ci if (m->status == -EINPROGRESS) 4788c2ecf20Sopenharmony_ci m->status = ret; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci spi_finalize_current_message(master); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci return ret; 4838c2ecf20Sopenharmony_ci} 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_cistatic int fsl_espi_setup(struct spi_device *spi) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci struct fsl_espi *espi; 4888c2ecf20Sopenharmony_ci u32 loop_mode; 4898c2ecf20Sopenharmony_ci struct fsl_espi_cs *cs = spi_get_ctldata(spi); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (!cs) { 4928c2ecf20Sopenharmony_ci cs = kzalloc(sizeof(*cs), GFP_KERNEL); 4938c2ecf20Sopenharmony_ci if (!cs) 4948c2ecf20Sopenharmony_ci return -ENOMEM; 4958c2ecf20Sopenharmony_ci spi_set_ctldata(spi, cs); 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci espi = spi_master_get_devdata(spi->master); 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci pm_runtime_get_sync(espi->dev); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci cs->hw_mode = fsl_espi_read_reg(espi, ESPI_SPMODEx(spi->chip_select)); 5038c2ecf20Sopenharmony_ci /* mask out bits we are going to set */ 5048c2ecf20Sopenharmony_ci cs->hw_mode &= ~(CSMODE_CP_BEGIN_EDGECLK | CSMODE_CI_INACTIVEHIGH 5058c2ecf20Sopenharmony_ci | CSMODE_REV); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPHA) 5088c2ecf20Sopenharmony_ci cs->hw_mode |= CSMODE_CP_BEGIN_EDGECLK; 5098c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPOL) 5108c2ecf20Sopenharmony_ci cs->hw_mode |= CSMODE_CI_INACTIVEHIGH; 5118c2ecf20Sopenharmony_ci if (!(spi->mode & SPI_LSB_FIRST)) 5128c2ecf20Sopenharmony_ci cs->hw_mode |= CSMODE_REV; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* Handle the loop mode */ 5158c2ecf20Sopenharmony_ci loop_mode = fsl_espi_read_reg(espi, ESPI_SPMODE); 5168c2ecf20Sopenharmony_ci loop_mode &= ~SPMODE_LOOP; 5178c2ecf20Sopenharmony_ci if (spi->mode & SPI_LOOP) 5188c2ecf20Sopenharmony_ci loop_mode |= SPMODE_LOOP; 5198c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPMODE, loop_mode); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci fsl_espi_setup_transfer(spi, NULL); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(espi->dev); 5248c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(espi->dev); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return 0; 5278c2ecf20Sopenharmony_ci} 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_cistatic void fsl_espi_cleanup(struct spi_device *spi) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci struct fsl_espi_cs *cs = spi_get_ctldata(spi); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci kfree(cs); 5348c2ecf20Sopenharmony_ci spi_set_ctldata(spi, NULL); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void fsl_espi_cpu_irq(struct fsl_espi *espi, u32 events) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci if (!espi->rx_done) 5408c2ecf20Sopenharmony_ci fsl_espi_read_rx_fifo(espi, events); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (!espi->tx_done) 5438c2ecf20Sopenharmony_ci fsl_espi_fill_tx_fifo(espi, events); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (!espi->tx_done || !espi->rx_done) 5468c2ecf20Sopenharmony_ci return; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* we're done, but check for errors before returning */ 5498c2ecf20Sopenharmony_ci events = fsl_espi_read_reg(espi, ESPI_SPIE); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (!(events & SPIE_DON)) 5528c2ecf20Sopenharmony_ci dev_err(espi->dev, 5538c2ecf20Sopenharmony_ci "Transfer done but SPIE_DON isn't set!\n"); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (SPIE_RXCNT(events) || SPIE_TXCNT(events) != FSL_ESPI_FIFO_SIZE) { 5568c2ecf20Sopenharmony_ci dev_err(espi->dev, "Transfer done but rx/tx fifo's aren't empty!\n"); 5578c2ecf20Sopenharmony_ci dev_err(espi->dev, "SPIE_RXCNT = %d, SPIE_TXCNT = %d\n", 5588c2ecf20Sopenharmony_ci SPIE_RXCNT(events), SPIE_TXCNT(events)); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci complete(&espi->done); 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic irqreturn_t fsl_espi_irq(s32 irq, void *context_data) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci struct fsl_espi *espi = context_data; 5678c2ecf20Sopenharmony_ci u32 events, mask; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci spin_lock(&espi->lock); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci /* Get interrupt events(tx/rx) */ 5728c2ecf20Sopenharmony_ci events = fsl_espi_read_reg(espi, ESPI_SPIE); 5738c2ecf20Sopenharmony_ci mask = fsl_espi_read_reg(espi, ESPI_SPIM); 5748c2ecf20Sopenharmony_ci if (!(events & mask)) { 5758c2ecf20Sopenharmony_ci spin_unlock(&espi->lock); 5768c2ecf20Sopenharmony_ci return IRQ_NONE; 5778c2ecf20Sopenharmony_ci } 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dev_vdbg(espi->dev, "%s: events %x\n", __func__, events); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci fsl_espi_cpu_irq(espi, events); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci /* Clear the events */ 5848c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPIE, events); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci spin_unlock(&espi->lock); 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 5928c2ecf20Sopenharmony_cistatic int fsl_espi_runtime_suspend(struct device *dev) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 5958c2ecf20Sopenharmony_ci struct fsl_espi *espi = spi_master_get_devdata(master); 5968c2ecf20Sopenharmony_ci u32 regval; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci regval = fsl_espi_read_reg(espi, ESPI_SPMODE); 5998c2ecf20Sopenharmony_ci regval &= ~SPMODE_ENABLE; 6008c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPMODE, regval); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci return 0; 6038c2ecf20Sopenharmony_ci} 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_cistatic int fsl_espi_runtime_resume(struct device *dev) 6068c2ecf20Sopenharmony_ci{ 6078c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 6088c2ecf20Sopenharmony_ci struct fsl_espi *espi = spi_master_get_devdata(master); 6098c2ecf20Sopenharmony_ci u32 regval; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci regval = fsl_espi_read_reg(espi, ESPI_SPMODE); 6128c2ecf20Sopenharmony_ci regval |= SPMODE_ENABLE; 6138c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPMODE, regval); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci#endif 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_cistatic size_t fsl_espi_max_message_size(struct spi_device *spi) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci return SPCOM_TRANLEN_MAX; 6228c2ecf20Sopenharmony_ci} 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic void fsl_espi_init_regs(struct device *dev, bool initial) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 6278c2ecf20Sopenharmony_ci struct fsl_espi *espi = spi_master_get_devdata(master); 6288c2ecf20Sopenharmony_ci struct device_node *nc; 6298c2ecf20Sopenharmony_ci u32 csmode, cs, prop; 6308c2ecf20Sopenharmony_ci int ret; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* SPI controller initializations */ 6338c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPMODE, 0); 6348c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPIM, 0); 6358c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPCOM, 0); 6368c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPIE, 0xffffffff); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Init eSPI CS mode register */ 6398c2ecf20Sopenharmony_ci for_each_available_child_of_node(master->dev.of_node, nc) { 6408c2ecf20Sopenharmony_ci /* get chip select */ 6418c2ecf20Sopenharmony_ci ret = of_property_read_u32(nc, "reg", &cs); 6428c2ecf20Sopenharmony_ci if (ret || cs >= master->num_chipselect) 6438c2ecf20Sopenharmony_ci continue; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci csmode = CSMODE_INIT_VAL; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci /* check if CSBEF is set in device tree */ 6488c2ecf20Sopenharmony_ci ret = of_property_read_u32(nc, "fsl,csbef", &prop); 6498c2ecf20Sopenharmony_ci if (!ret) { 6508c2ecf20Sopenharmony_ci csmode &= ~(CSMODE_BEF(0xf)); 6518c2ecf20Sopenharmony_ci csmode |= CSMODE_BEF(prop); 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci /* check if CSAFT is set in device tree */ 6558c2ecf20Sopenharmony_ci ret = of_property_read_u32(nc, "fsl,csaft", &prop); 6568c2ecf20Sopenharmony_ci if (!ret) { 6578c2ecf20Sopenharmony_ci csmode &= ~(CSMODE_AFT(0xf)); 6588c2ecf20Sopenharmony_ci csmode |= CSMODE_AFT(prop); 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPMODEx(cs), csmode); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci if (initial) 6648c2ecf20Sopenharmony_ci dev_info(dev, "cs=%u, init_csmode=0x%x\n", cs, csmode); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci /* Enable SPI interface */ 6688c2ecf20Sopenharmony_ci fsl_espi_write_reg(espi, ESPI_SPMODE, SPMODE_INIT_VAL | SPMODE_ENABLE); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic int fsl_espi_probe(struct device *dev, struct resource *mem, 6728c2ecf20Sopenharmony_ci unsigned int irq, unsigned int num_cs) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci struct spi_master *master; 6758c2ecf20Sopenharmony_ci struct fsl_espi *espi; 6768c2ecf20Sopenharmony_ci int ret; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci master = spi_alloc_master(dev, sizeof(struct fsl_espi)); 6798c2ecf20Sopenharmony_ci if (!master) 6808c2ecf20Sopenharmony_ci return -ENOMEM; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci dev_set_drvdata(dev, master); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci master->mode_bits = SPI_RX_DUAL | SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | 6858c2ecf20Sopenharmony_ci SPI_LSB_FIRST | SPI_LOOP; 6868c2ecf20Sopenharmony_ci master->dev.of_node = dev->of_node; 6878c2ecf20Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16); 6888c2ecf20Sopenharmony_ci master->setup = fsl_espi_setup; 6898c2ecf20Sopenharmony_ci master->cleanup = fsl_espi_cleanup; 6908c2ecf20Sopenharmony_ci master->transfer_one_message = fsl_espi_do_one_msg; 6918c2ecf20Sopenharmony_ci master->auto_runtime_pm = true; 6928c2ecf20Sopenharmony_ci master->max_message_size = fsl_espi_max_message_size; 6938c2ecf20Sopenharmony_ci master->num_chipselect = num_cs; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci espi = spi_master_get_devdata(master); 6968c2ecf20Sopenharmony_ci spin_lock_init(&espi->lock); 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci espi->dev = dev; 6998c2ecf20Sopenharmony_ci espi->spibrg = fsl_get_sys_freq(); 7008c2ecf20Sopenharmony_ci if (espi->spibrg == -1) { 7018c2ecf20Sopenharmony_ci dev_err(dev, "Can't get sys frequency!\n"); 7028c2ecf20Sopenharmony_ci ret = -EINVAL; 7038c2ecf20Sopenharmony_ci goto err_probe; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci /* determined by clock divider fields DIV16/PM in register SPMODEx */ 7068c2ecf20Sopenharmony_ci master->min_speed_hz = DIV_ROUND_UP(espi->spibrg, 4 * 16 * 16); 7078c2ecf20Sopenharmony_ci master->max_speed_hz = DIV_ROUND_UP(espi->spibrg, 4); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci init_completion(&espi->done); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci espi->reg_base = devm_ioremap_resource(dev, mem); 7128c2ecf20Sopenharmony_ci if (IS_ERR(espi->reg_base)) { 7138c2ecf20Sopenharmony_ci ret = PTR_ERR(espi->reg_base); 7148c2ecf20Sopenharmony_ci goto err_probe; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Register for SPI Interrupt */ 7188c2ecf20Sopenharmony_ci ret = devm_request_irq(dev, irq, fsl_espi_irq, 0, "fsl_espi", espi); 7198c2ecf20Sopenharmony_ci if (ret) 7208c2ecf20Sopenharmony_ci goto err_probe; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci fsl_espi_init_regs(dev, true); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_TIMEOUT); 7258c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 7268c2ecf20Sopenharmony_ci pm_runtime_set_active(dev); 7278c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 7288c2ecf20Sopenharmony_ci pm_runtime_get_sync(dev); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci ret = devm_spi_register_master(dev, master); 7318c2ecf20Sopenharmony_ci if (ret < 0) 7328c2ecf20Sopenharmony_ci goto err_pm; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci dev_info(dev, "irq = %u\n", irq); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 7378c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci return 0; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cierr_pm: 7428c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 7438c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 7448c2ecf20Sopenharmony_ci pm_runtime_set_suspended(dev); 7458c2ecf20Sopenharmony_cierr_probe: 7468c2ecf20Sopenharmony_ci spi_master_put(master); 7478c2ecf20Sopenharmony_ci return ret; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_cistatic int of_fsl_espi_get_chipselects(struct device *dev) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 7538c2ecf20Sopenharmony_ci u32 num_cs; 7548c2ecf20Sopenharmony_ci int ret; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci ret = of_property_read_u32(np, "fsl,espi-num-chipselects", &num_cs); 7578c2ecf20Sopenharmony_ci if (ret) { 7588c2ecf20Sopenharmony_ci dev_err(dev, "No 'fsl,espi-num-chipselects' property\n"); 7598c2ecf20Sopenharmony_ci return 0; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci return num_cs; 7638c2ecf20Sopenharmony_ci} 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_cistatic int of_fsl_espi_probe(struct platform_device *ofdev) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct device *dev = &ofdev->dev; 7688c2ecf20Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 7698c2ecf20Sopenharmony_ci struct resource mem; 7708c2ecf20Sopenharmony_ci unsigned int irq, num_cs; 7718c2ecf20Sopenharmony_ci int ret; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci if (of_property_read_bool(np, "mode")) { 7748c2ecf20Sopenharmony_ci dev_err(dev, "mode property is not supported on ESPI!\n"); 7758c2ecf20Sopenharmony_ci return -EINVAL; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci num_cs = of_fsl_espi_get_chipselects(dev); 7798c2ecf20Sopenharmony_ci if (!num_cs) 7808c2ecf20Sopenharmony_ci return -EINVAL; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci ret = of_address_to_resource(np, 0, &mem); 7838c2ecf20Sopenharmony_ci if (ret) 7848c2ecf20Sopenharmony_ci return ret; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(np, 0); 7878c2ecf20Sopenharmony_ci if (!irq) 7888c2ecf20Sopenharmony_ci return -EINVAL; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci return fsl_espi_probe(dev, &mem, irq, num_cs); 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic int of_fsl_espi_remove(struct platform_device *dev) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci pm_runtime_disable(&dev->dev); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci return 0; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 8018c2ecf20Sopenharmony_cistatic int of_fsl_espi_suspend(struct device *dev) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 8048c2ecf20Sopenharmony_ci int ret; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci ret = spi_master_suspend(master); 8078c2ecf20Sopenharmony_ci if (ret) 8088c2ecf20Sopenharmony_ci return ret; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci return pm_runtime_force_suspend(dev); 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic int of_fsl_espi_resume(struct device *dev) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 8168c2ecf20Sopenharmony_ci int ret; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci fsl_espi_init_regs(dev, false); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci ret = pm_runtime_force_resume(dev); 8218c2ecf20Sopenharmony_ci if (ret < 0) 8228c2ecf20Sopenharmony_ci return ret; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci return spi_master_resume(master); 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic const struct dev_pm_ops espi_pm = { 8298c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(fsl_espi_runtime_suspend, 8308c2ecf20Sopenharmony_ci fsl_espi_runtime_resume, NULL) 8318c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(of_fsl_espi_suspend, of_fsl_espi_resume) 8328c2ecf20Sopenharmony_ci}; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_cistatic const struct of_device_id of_fsl_espi_match[] = { 8358c2ecf20Sopenharmony_ci { .compatible = "fsl,mpc8536-espi" }, 8368c2ecf20Sopenharmony_ci {} 8378c2ecf20Sopenharmony_ci}; 8388c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_fsl_espi_match); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic struct platform_driver fsl_espi_driver = { 8418c2ecf20Sopenharmony_ci .driver = { 8428c2ecf20Sopenharmony_ci .name = "fsl_espi", 8438c2ecf20Sopenharmony_ci .of_match_table = of_fsl_espi_match, 8448c2ecf20Sopenharmony_ci .pm = &espi_pm, 8458c2ecf20Sopenharmony_ci }, 8468c2ecf20Sopenharmony_ci .probe = of_fsl_espi_probe, 8478c2ecf20Sopenharmony_ci .remove = of_fsl_espi_remove, 8488c2ecf20Sopenharmony_ci}; 8498c2ecf20Sopenharmony_cimodule_platform_driver(fsl_espi_driver); 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mingkai Hu"); 8528c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Enhanced Freescale SPI Driver"); 8538c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 854