18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Designware SPI core controller driver (refer pxa2xx_spi.c)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2009, Intel Corporation.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
98c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/preempt.h>
128c2ecf20Sopenharmony_ci#include <linux/highmem.h>
138c2ecf20Sopenharmony_ci#include <linux/delay.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/spi/spi.h>
168c2ecf20Sopenharmony_ci#include <linux/spi/spi-mem.h>
178c2ecf20Sopenharmony_ci#include <linux/string.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "spi-dw.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
238c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
248c2ecf20Sopenharmony_ci#endif
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* Slave spi_device related */
278c2ecf20Sopenharmony_cistruct chip_data {
288c2ecf20Sopenharmony_ci	u32 cr0;
298c2ecf20Sopenharmony_ci	u32 rx_sample_dly;	/* RX sample delay */
308c2ecf20Sopenharmony_ci};
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define DW_SPI_DBGFS_REG(_name, _off)	\
358c2ecf20Sopenharmony_ci{					\
368c2ecf20Sopenharmony_ci	.name = _name,			\
378c2ecf20Sopenharmony_ci	.offset = _off,			\
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const struct debugfs_reg32 dw_spi_dbgfs_regs[] = {
418c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("CTRLR0", DW_SPI_CTRLR0),
428c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("CTRLR1", DW_SPI_CTRLR1),
438c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("SSIENR", DW_SPI_SSIENR),
448c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("SER", DW_SPI_SER),
458c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("BAUDR", DW_SPI_BAUDR),
468c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("TXFTLR", DW_SPI_TXFTLR),
478c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("RXFTLR", DW_SPI_RXFTLR),
488c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("TXFLR", DW_SPI_TXFLR),
498c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("RXFLR", DW_SPI_RXFLR),
508c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("SR", DW_SPI_SR),
518c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("IMR", DW_SPI_IMR),
528c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("ISR", DW_SPI_ISR),
538c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR),
548c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR),
558c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR),
568c2ecf20Sopenharmony_ci	DW_SPI_DBGFS_REG("RX_SAMPLE_DLY", DW_SPI_RX_SAMPLE_DLY),
578c2ecf20Sopenharmony_ci};
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int dw_spi_debugfs_init(struct dw_spi *dws)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	char name[32];
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	snprintf(name, 32, "dw_spi%d", dws->master->bus_num);
648c2ecf20Sopenharmony_ci	dws->debugfs = debugfs_create_dir(name, NULL);
658c2ecf20Sopenharmony_ci	if (!dws->debugfs)
668c2ecf20Sopenharmony_ci		return -ENOMEM;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	dws->regset.regs = dw_spi_dbgfs_regs;
698c2ecf20Sopenharmony_ci	dws->regset.nregs = ARRAY_SIZE(dw_spi_dbgfs_regs);
708c2ecf20Sopenharmony_ci	dws->regset.base = dws->regs;
718c2ecf20Sopenharmony_ci	debugfs_create_regset32("registers", 0400, dws->debugfs, &dws->regset);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic void dw_spi_debugfs_remove(struct dw_spi *dws)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	debugfs_remove_recursive(dws->debugfs);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci#else
828c2ecf20Sopenharmony_cistatic inline int dw_spi_debugfs_init(struct dw_spi *dws)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	return 0;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline void dw_spi_debugfs_remove(struct dw_spi *dws)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_civoid dw_spi_set_cs(struct spi_device *spi, bool enable)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
958c2ecf20Sopenharmony_ci	bool cs_high = !!(spi->mode & SPI_CS_HIGH);
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	/*
988c2ecf20Sopenharmony_ci	 * DW SPI controller demands any native CS being set in order to
998c2ecf20Sopenharmony_ci	 * proceed with data transfer. So in order to activate the SPI
1008c2ecf20Sopenharmony_ci	 * communications we must set a corresponding bit in the Slave
1018c2ecf20Sopenharmony_ci	 * Enable register no matter whether the SPI core is configured to
1028c2ecf20Sopenharmony_ci	 * support active-high or active-low CS level.
1038c2ecf20Sopenharmony_ci	 */
1048c2ecf20Sopenharmony_ci	if (cs_high == enable)
1058c2ecf20Sopenharmony_ci		dw_writel(dws, DW_SPI_SER, BIT(spi->chip_select));
1068c2ecf20Sopenharmony_ci	else
1078c2ecf20Sopenharmony_ci		dw_writel(dws, DW_SPI_SER, 0);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_spi_set_cs);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci/* Return the max entries we can fill into tx fifo */
1128c2ecf20Sopenharmony_cistatic inline u32 tx_max(struct dw_spi *dws)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	u32 tx_room, rxtx_gap;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	tx_room = dws->fifo_len - dw_readl(dws, DW_SPI_TXFLR);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	/*
1198c2ecf20Sopenharmony_ci	 * Another concern is about the tx/rx mismatch, we
1208c2ecf20Sopenharmony_ci	 * though to use (dws->fifo_len - rxflr - txflr) as
1218c2ecf20Sopenharmony_ci	 * one maximum value for tx, but it doesn't cover the
1228c2ecf20Sopenharmony_ci	 * data which is out of tx/rx fifo and inside the
1238c2ecf20Sopenharmony_ci	 * shift registers. So a control from sw point of
1248c2ecf20Sopenharmony_ci	 * view is taken.
1258c2ecf20Sopenharmony_ci	 */
1268c2ecf20Sopenharmony_ci	rxtx_gap = dws->fifo_len - (dws->rx_len - dws->tx_len);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return min3((u32)dws->tx_len, tx_room, rxtx_gap);
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/* Return the max entries we should read out of rx fifo */
1328c2ecf20Sopenharmony_cistatic inline u32 rx_max(struct dw_spi *dws)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	return min_t(u32, dws->rx_len, dw_readl(dws, DW_SPI_RXFLR));
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void dw_writer(struct dw_spi *dws)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	u32 max = tx_max(dws);
1408c2ecf20Sopenharmony_ci	u16 txw = 0;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	while (max--) {
1438c2ecf20Sopenharmony_ci		if (dws->tx) {
1448c2ecf20Sopenharmony_ci			if (dws->n_bytes == 1)
1458c2ecf20Sopenharmony_ci				txw = *(u8 *)(dws->tx);
1468c2ecf20Sopenharmony_ci			else
1478c2ecf20Sopenharmony_ci				txw = *(u16 *)(dws->tx);
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci			dws->tx += dws->n_bytes;
1508c2ecf20Sopenharmony_ci		}
1518c2ecf20Sopenharmony_ci		dw_write_io_reg(dws, DW_SPI_DR, txw);
1528c2ecf20Sopenharmony_ci		--dws->tx_len;
1538c2ecf20Sopenharmony_ci	}
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_cistatic void dw_reader(struct dw_spi *dws)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	u32 max = rx_max(dws);
1598c2ecf20Sopenharmony_ci	u16 rxw;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	while (max--) {
1628c2ecf20Sopenharmony_ci		rxw = dw_read_io_reg(dws, DW_SPI_DR);
1638c2ecf20Sopenharmony_ci		if (dws->rx) {
1648c2ecf20Sopenharmony_ci			if (dws->n_bytes == 1)
1658c2ecf20Sopenharmony_ci				*(u8 *)(dws->rx) = rxw;
1668c2ecf20Sopenharmony_ci			else
1678c2ecf20Sopenharmony_ci				*(u16 *)(dws->rx) = rxw;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci			dws->rx += dws->n_bytes;
1708c2ecf20Sopenharmony_ci		}
1718c2ecf20Sopenharmony_ci		--dws->rx_len;
1728c2ecf20Sopenharmony_ci	}
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ciint dw_spi_check_status(struct dw_spi *dws, bool raw)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	u32 irq_status;
1788c2ecf20Sopenharmony_ci	int ret = 0;
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	if (raw)
1818c2ecf20Sopenharmony_ci		irq_status = dw_readl(dws, DW_SPI_RISR);
1828c2ecf20Sopenharmony_ci	else
1838c2ecf20Sopenharmony_ci		irq_status = dw_readl(dws, DW_SPI_ISR);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (irq_status & SPI_INT_RXOI) {
1868c2ecf20Sopenharmony_ci		dev_err(&dws->master->dev, "RX FIFO overflow detected\n");
1878c2ecf20Sopenharmony_ci		ret = -EIO;
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	if (irq_status & SPI_INT_RXUI) {
1918c2ecf20Sopenharmony_ci		dev_err(&dws->master->dev, "RX FIFO underflow detected\n");
1928c2ecf20Sopenharmony_ci		ret = -EIO;
1938c2ecf20Sopenharmony_ci	}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	if (irq_status & SPI_INT_TXOI) {
1968c2ecf20Sopenharmony_ci		dev_err(&dws->master->dev, "TX FIFO overflow detected\n");
1978c2ecf20Sopenharmony_ci		ret = -EIO;
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* Generically handle the erroneous situation */
2018c2ecf20Sopenharmony_ci	if (ret) {
2028c2ecf20Sopenharmony_ci		spi_reset_chip(dws);
2038c2ecf20Sopenharmony_ci		if (dws->master->cur_msg)
2048c2ecf20Sopenharmony_ci			dws->master->cur_msg->status = ret;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	return ret;
2088c2ecf20Sopenharmony_ci}
2098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_spi_check_status);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic irqreturn_t dw_spi_transfer_handler(struct dw_spi *dws)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	u16 irq_status = dw_readl(dws, DW_SPI_ISR);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	if (dw_spi_check_status(dws, false)) {
2168c2ecf20Sopenharmony_ci		spi_finalize_current_transfer(dws->master);
2178c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
2188c2ecf20Sopenharmony_ci	}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	/*
2218c2ecf20Sopenharmony_ci	 * Read data from the Rx FIFO every time we've got a chance executing
2228c2ecf20Sopenharmony_ci	 * this method. If there is nothing left to receive, terminate the
2238c2ecf20Sopenharmony_ci	 * procedure. Otherwise adjust the Rx FIFO Threshold level if it's a
2248c2ecf20Sopenharmony_ci	 * final stage of the transfer. By doing so we'll get the next IRQ
2258c2ecf20Sopenharmony_ci	 * right when the leftover incoming data is received.
2268c2ecf20Sopenharmony_ci	 */
2278c2ecf20Sopenharmony_ci	dw_reader(dws);
2288c2ecf20Sopenharmony_ci	if (!dws->rx_len) {
2298c2ecf20Sopenharmony_ci		spi_mask_intr(dws, 0xff);
2308c2ecf20Sopenharmony_ci		spi_finalize_current_transfer(dws->master);
2318c2ecf20Sopenharmony_ci	} else if (dws->rx_len <= dw_readl(dws, DW_SPI_RXFTLR)) {
2328c2ecf20Sopenharmony_ci		dw_writel(dws, DW_SPI_RXFTLR, dws->rx_len - 1);
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	/*
2368c2ecf20Sopenharmony_ci	 * Send data out if Tx FIFO Empty IRQ is received. The IRQ will be
2378c2ecf20Sopenharmony_ci	 * disabled after the data transmission is finished so not to
2388c2ecf20Sopenharmony_ci	 * have the TXE IRQ flood at the final stage of the transfer.
2398c2ecf20Sopenharmony_ci	 */
2408c2ecf20Sopenharmony_ci	if (irq_status & SPI_INT_TXEI) {
2418c2ecf20Sopenharmony_ci		dw_writer(dws);
2428c2ecf20Sopenharmony_ci		if (!dws->tx_len)
2438c2ecf20Sopenharmony_ci			spi_mask_intr(dws, SPI_INT_TXEI);
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_cistatic irqreturn_t dw_spi_irq(int irq, void *dev_id)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct spi_controller *master = dev_id;
2528c2ecf20Sopenharmony_ci	struct dw_spi *dws = spi_controller_get_devdata(master);
2538c2ecf20Sopenharmony_ci	u16 irq_status = dw_readl(dws, DW_SPI_ISR) & 0x3f;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if (!irq_status)
2568c2ecf20Sopenharmony_ci		return IRQ_NONE;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci	if (!master->cur_msg) {
2598c2ecf20Sopenharmony_ci		spi_mask_intr(dws, 0xff);
2608c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return dws->transfer_handler(dws);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	u32 cr0 = 0;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
2718c2ecf20Sopenharmony_ci		/* CTRLR0[ 5: 4] Frame Format */
2728c2ecf20Sopenharmony_ci		cr0 |= SSI_MOTO_SPI << SPI_FRF_OFFSET;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci		/*
2758c2ecf20Sopenharmony_ci		 * SPI mode (SCPOL|SCPH)
2768c2ecf20Sopenharmony_ci		 * CTRLR0[ 6] Serial Clock Phase
2778c2ecf20Sopenharmony_ci		 * CTRLR0[ 7] Serial Clock Polarity
2788c2ecf20Sopenharmony_ci		 */
2798c2ecf20Sopenharmony_ci		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << SPI_SCOL_OFFSET;
2808c2ecf20Sopenharmony_ci		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << SPI_SCPH_OFFSET;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci		/* CTRLR0[11] Shift Register Loop */
2838c2ecf20Sopenharmony_ci		cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET;
2848c2ecf20Sopenharmony_ci	} else {
2858c2ecf20Sopenharmony_ci		/* CTRLR0[ 7: 6] Frame Format */
2868c2ecf20Sopenharmony_ci		cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci		/*
2898c2ecf20Sopenharmony_ci		 * SPI mode (SCPOL|SCPH)
2908c2ecf20Sopenharmony_ci		 * CTRLR0[ 8] Serial Clock Phase
2918c2ecf20Sopenharmony_ci		 * CTRLR0[ 9] Serial Clock Polarity
2928c2ecf20Sopenharmony_ci		 */
2938c2ecf20Sopenharmony_ci		cr0 |= ((spi->mode & SPI_CPOL) ? 1 : 0) << DWC_SSI_CTRLR0_SCPOL_OFFSET;
2948c2ecf20Sopenharmony_ci		cr0 |= ((spi->mode & SPI_CPHA) ? 1 : 0) << DWC_SSI_CTRLR0_SCPH_OFFSET;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci		/* CTRLR0[13] Shift Register Loop */
2978c2ecf20Sopenharmony_ci		cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci		if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
3008c2ecf20Sopenharmony_ci			cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
3018c2ecf20Sopenharmony_ci	}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return cr0;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_civoid dw_spi_update_config(struct dw_spi *dws, struct spi_device *spi,
3078c2ecf20Sopenharmony_ci			  struct dw_spi_cfg *cfg)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct chip_data *chip = spi_get_ctldata(spi);
3108c2ecf20Sopenharmony_ci	u32 cr0 = chip->cr0;
3118c2ecf20Sopenharmony_ci	u32 speed_hz;
3128c2ecf20Sopenharmony_ci	u16 clk_div;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* CTRLR0[ 4/3: 0] Data Frame Size */
3158c2ecf20Sopenharmony_ci	cr0 |= (cfg->dfs - 1);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
3188c2ecf20Sopenharmony_ci		/* CTRLR0[ 9:8] Transfer Mode */
3198c2ecf20Sopenharmony_ci		cr0 |= cfg->tmode << SPI_TMOD_OFFSET;
3208c2ecf20Sopenharmony_ci	else
3218c2ecf20Sopenharmony_ci		/* CTRLR0[11:10] Transfer Mode */
3228c2ecf20Sopenharmony_ci		cr0 |= cfg->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	dw_writel(dws, DW_SPI_CTRLR0, cr0);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (cfg->tmode == SPI_TMOD_EPROMREAD || cfg->tmode == SPI_TMOD_RO)
3278c2ecf20Sopenharmony_ci		dw_writel(dws, DW_SPI_CTRLR1, cfg->ndf ? cfg->ndf - 1 : 0);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/* Note DW APB SSI clock divider doesn't support odd numbers */
3308c2ecf20Sopenharmony_ci	clk_div = (DIV_ROUND_UP(dws->max_freq, cfg->freq) + 1) & 0xfffe;
3318c2ecf20Sopenharmony_ci	speed_hz = dws->max_freq / clk_div;
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (dws->current_freq != speed_hz) {
3348c2ecf20Sopenharmony_ci		spi_set_clk(dws, clk_div);
3358c2ecf20Sopenharmony_ci		dws->current_freq = speed_hz;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/* Update RX sample delay if required */
3398c2ecf20Sopenharmony_ci	if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
3408c2ecf20Sopenharmony_ci		dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
3418c2ecf20Sopenharmony_ci		dws->cur_rx_sample_dly = chip->rx_sample_dly;
3428c2ecf20Sopenharmony_ci	}
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_spi_update_config);
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic void dw_spi_irq_setup(struct dw_spi *dws)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	u16 level;
3498c2ecf20Sopenharmony_ci	u8 imask;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	/*
3528c2ecf20Sopenharmony_ci	 * Originally Tx and Rx data lengths match. Rx FIFO Threshold level
3538c2ecf20Sopenharmony_ci	 * will be adjusted at the final stage of the IRQ-based SPI transfer
3548c2ecf20Sopenharmony_ci	 * execution so not to lose the leftover of the incoming data.
3558c2ecf20Sopenharmony_ci	 */
3568c2ecf20Sopenharmony_ci	level = min_t(unsigned int, dws->fifo_len / 2, dws->tx_len);
3578c2ecf20Sopenharmony_ci	dw_writel(dws, DW_SPI_TXFTLR, level);
3588c2ecf20Sopenharmony_ci	dw_writel(dws, DW_SPI_RXFTLR, level - 1);
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	dws->transfer_handler = dw_spi_transfer_handler;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	imask = SPI_INT_TXEI | SPI_INT_TXOI | SPI_INT_RXUI | SPI_INT_RXOI |
3638c2ecf20Sopenharmony_ci		SPI_INT_RXFI;
3648c2ecf20Sopenharmony_ci	spi_umask_intr(dws, imask);
3658c2ecf20Sopenharmony_ci}
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci/*
3688c2ecf20Sopenharmony_ci * The iterative procedure of the poll-based transfer is simple: write as much
3698c2ecf20Sopenharmony_ci * as possible to the Tx FIFO, wait until the pending to receive data is ready
3708c2ecf20Sopenharmony_ci * to be read, read it from the Rx FIFO and check whether the performed
3718c2ecf20Sopenharmony_ci * procedure has been successful.
3728c2ecf20Sopenharmony_ci *
3738c2ecf20Sopenharmony_ci * Note this method the same way as the IRQ-based transfer won't work well for
3748c2ecf20Sopenharmony_ci * the SPI devices connected to the controller with native CS due to the
3758c2ecf20Sopenharmony_ci * automatic CS assertion/de-assertion.
3768c2ecf20Sopenharmony_ci */
3778c2ecf20Sopenharmony_cistatic int dw_spi_poll_transfer(struct dw_spi *dws,
3788c2ecf20Sopenharmony_ci				struct spi_transfer *transfer)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct spi_delay delay;
3818c2ecf20Sopenharmony_ci	u16 nbits;
3828c2ecf20Sopenharmony_ci	int ret;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	delay.unit = SPI_DELAY_UNIT_SCK;
3858c2ecf20Sopenharmony_ci	nbits = dws->n_bytes * BITS_PER_BYTE;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	do {
3888c2ecf20Sopenharmony_ci		dw_writer(dws);
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci		delay.value = nbits * (dws->rx_len - dws->tx_len);
3918c2ecf20Sopenharmony_ci		spi_delay_exec(&delay, transfer);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci		dw_reader(dws);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci		ret = dw_spi_check_status(dws, true);
3968c2ecf20Sopenharmony_ci		if (ret)
3978c2ecf20Sopenharmony_ci			return ret;
3988c2ecf20Sopenharmony_ci	} while (dws->rx_len);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	return 0;
4018c2ecf20Sopenharmony_ci}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_cistatic int dw_spi_transfer_one(struct spi_controller *master,
4048c2ecf20Sopenharmony_ci		struct spi_device *spi, struct spi_transfer *transfer)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct dw_spi *dws = spi_controller_get_devdata(master);
4078c2ecf20Sopenharmony_ci	struct dw_spi_cfg cfg = {
4088c2ecf20Sopenharmony_ci		.tmode = SPI_TMOD_TR,
4098c2ecf20Sopenharmony_ci		.dfs = transfer->bits_per_word,
4108c2ecf20Sopenharmony_ci		.freq = transfer->speed_hz,
4118c2ecf20Sopenharmony_ci	};
4128c2ecf20Sopenharmony_ci	int ret;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	dws->dma_mapped = 0;
4158c2ecf20Sopenharmony_ci	dws->n_bytes = DIV_ROUND_UP(transfer->bits_per_word, BITS_PER_BYTE);
4168c2ecf20Sopenharmony_ci	dws->tx = (void *)transfer->tx_buf;
4178c2ecf20Sopenharmony_ci	dws->tx_len = transfer->len / dws->n_bytes;
4188c2ecf20Sopenharmony_ci	dws->rx = transfer->rx_buf;
4198c2ecf20Sopenharmony_ci	dws->rx_len = dws->tx_len;
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	/* Ensure the data above is visible for all CPUs */
4228c2ecf20Sopenharmony_ci	smp_mb();
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	spi_enable_chip(dws, 0);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	dw_spi_update_config(dws, spi, &cfg);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	transfer->effective_speed_hz = dws->current_freq;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* Check if current transfer is a DMA transaction */
4318c2ecf20Sopenharmony_ci	if (master->can_dma && master->can_dma(master, spi, transfer))
4328c2ecf20Sopenharmony_ci		dws->dma_mapped = master->cur_msg_mapped;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* For poll mode just disable all interrupts */
4358c2ecf20Sopenharmony_ci	spi_mask_intr(dws, 0xff);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if (dws->dma_mapped) {
4388c2ecf20Sopenharmony_ci		ret = dws->dma_ops->dma_setup(dws, transfer);
4398c2ecf20Sopenharmony_ci		if (ret)
4408c2ecf20Sopenharmony_ci			return ret;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	spi_enable_chip(dws, 1);
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if (dws->dma_mapped)
4468c2ecf20Sopenharmony_ci		return dws->dma_ops->dma_transfer(dws, transfer);
4478c2ecf20Sopenharmony_ci	else if (dws->irq == IRQ_NOTCONNECTED)
4488c2ecf20Sopenharmony_ci		return dw_spi_poll_transfer(dws, transfer);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	dw_spi_irq_setup(dws);
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	return 1;
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic void dw_spi_handle_err(struct spi_controller *master,
4568c2ecf20Sopenharmony_ci		struct spi_message *msg)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	struct dw_spi *dws = spi_controller_get_devdata(master);
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	if (dws->dma_mapped)
4618c2ecf20Sopenharmony_ci		dws->dma_ops->dma_stop(dws);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	spi_reset_chip(dws);
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic int dw_spi_adjust_mem_op_size(struct spi_mem *mem, struct spi_mem_op *op)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN)
4698c2ecf20Sopenharmony_ci		op->data.nbytes = clamp_val(op->data.nbytes, 0, SPI_NDF_MASK + 1);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	return 0;
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_cistatic bool dw_spi_supports_mem_op(struct spi_mem *mem,
4758c2ecf20Sopenharmony_ci				   const struct spi_mem_op *op)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	if (op->data.buswidth > 1 || op->addr.buswidth > 1 ||
4788c2ecf20Sopenharmony_ci	    op->dummy.buswidth > 1 || op->cmd.buswidth > 1)
4798c2ecf20Sopenharmony_ci		return false;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return spi_mem_default_supports_op(mem, op);
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic int dw_spi_init_mem_buf(struct dw_spi *dws, const struct spi_mem_op *op)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	unsigned int i, j, len;
4878c2ecf20Sopenharmony_ci	u8 *out;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	/*
4908c2ecf20Sopenharmony_ci	 * Calculate the total length of the EEPROM command transfer and
4918c2ecf20Sopenharmony_ci	 * either use the pre-allocated buffer or create a temporary one.
4928c2ecf20Sopenharmony_ci	 */
4938c2ecf20Sopenharmony_ci	len = op->cmd.nbytes + op->addr.nbytes + op->dummy.nbytes;
4948c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_OUT)
4958c2ecf20Sopenharmony_ci		len += op->data.nbytes;
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_ci	if (len <= SPI_BUF_SIZE) {
4988c2ecf20Sopenharmony_ci		out = dws->buf;
4998c2ecf20Sopenharmony_ci	} else {
5008c2ecf20Sopenharmony_ci		out = kzalloc(len, GFP_KERNEL);
5018c2ecf20Sopenharmony_ci		if (!out)
5028c2ecf20Sopenharmony_ci			return -ENOMEM;
5038c2ecf20Sopenharmony_ci	}
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/*
5068c2ecf20Sopenharmony_ci	 * Collect the operation code, address and dummy bytes into the single
5078c2ecf20Sopenharmony_ci	 * buffer. If it's a transfer with data to be sent, also copy it into the
5088c2ecf20Sopenharmony_ci	 * single buffer in order to speed the data transmission up.
5098c2ecf20Sopenharmony_ci	 */
5108c2ecf20Sopenharmony_ci	for (i = 0; i < op->cmd.nbytes; ++i)
5118c2ecf20Sopenharmony_ci		out[i] = SPI_GET_BYTE(op->cmd.opcode, op->cmd.nbytes - i - 1);
5128c2ecf20Sopenharmony_ci	for (j = 0; j < op->addr.nbytes; ++i, ++j)
5138c2ecf20Sopenharmony_ci		out[i] = SPI_GET_BYTE(op->addr.val, op->addr.nbytes - j - 1);
5148c2ecf20Sopenharmony_ci	for (j = 0; j < op->dummy.nbytes; ++i, ++j)
5158c2ecf20Sopenharmony_ci		out[i] = 0x0;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_OUT)
5188c2ecf20Sopenharmony_ci		memcpy(&out[i], op->data.buf.out, op->data.nbytes);
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	dws->n_bytes = 1;
5218c2ecf20Sopenharmony_ci	dws->tx = out;
5228c2ecf20Sopenharmony_ci	dws->tx_len = len;
5238c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
5248c2ecf20Sopenharmony_ci		dws->rx = op->data.buf.in;
5258c2ecf20Sopenharmony_ci		dws->rx_len = op->data.nbytes;
5268c2ecf20Sopenharmony_ci	} else {
5278c2ecf20Sopenharmony_ci		dws->rx = NULL;
5288c2ecf20Sopenharmony_ci		dws->rx_len = 0;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	return 0;
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic void dw_spi_free_mem_buf(struct dw_spi *dws)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	if (dws->tx != dws->buf)
5378c2ecf20Sopenharmony_ci		kfree(dws->tx);
5388c2ecf20Sopenharmony_ci}
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_cistatic int dw_spi_write_then_read(struct dw_spi *dws, struct spi_device *spi)
5418c2ecf20Sopenharmony_ci{
5428c2ecf20Sopenharmony_ci	u32 room, entries, sts;
5438c2ecf20Sopenharmony_ci	unsigned int len;
5448c2ecf20Sopenharmony_ci	u8 *buf;
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	/*
5478c2ecf20Sopenharmony_ci	 * At initial stage we just pre-fill the Tx FIFO in with no rush,
5488c2ecf20Sopenharmony_ci	 * since native CS hasn't been enabled yet and the automatic data
5498c2ecf20Sopenharmony_ci	 * transmission won't start til we do that.
5508c2ecf20Sopenharmony_ci	 */
5518c2ecf20Sopenharmony_ci	len = min(dws->fifo_len, dws->tx_len);
5528c2ecf20Sopenharmony_ci	buf = dws->tx;
5538c2ecf20Sopenharmony_ci	while (len--)
5548c2ecf20Sopenharmony_ci		dw_write_io_reg(dws, DW_SPI_DR, *buf++);
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	/*
5578c2ecf20Sopenharmony_ci	 * After setting any bit in the SER register the transmission will
5588c2ecf20Sopenharmony_ci	 * start automatically. We have to keep up with that procedure
5598c2ecf20Sopenharmony_ci	 * otherwise the CS de-assertion will happen whereupon the memory
5608c2ecf20Sopenharmony_ci	 * operation will be pre-terminated.
5618c2ecf20Sopenharmony_ci	 */
5628c2ecf20Sopenharmony_ci	len = dws->tx_len - ((void *)buf - dws->tx);
5638c2ecf20Sopenharmony_ci	dw_spi_set_cs(spi, false);
5648c2ecf20Sopenharmony_ci	while (len) {
5658c2ecf20Sopenharmony_ci		entries = readl_relaxed(dws->regs + DW_SPI_TXFLR);
5668c2ecf20Sopenharmony_ci		if (!entries) {
5678c2ecf20Sopenharmony_ci			dev_err(&dws->master->dev, "CS de-assertion on Tx\n");
5688c2ecf20Sopenharmony_ci			return -EIO;
5698c2ecf20Sopenharmony_ci		}
5708c2ecf20Sopenharmony_ci		room = min(dws->fifo_len - entries, len);
5718c2ecf20Sopenharmony_ci		for (; room; --room, --len)
5728c2ecf20Sopenharmony_ci			dw_write_io_reg(dws, DW_SPI_DR, *buf++);
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	/*
5768c2ecf20Sopenharmony_ci	 * Data fetching will start automatically if the EEPROM-read mode is
5778c2ecf20Sopenharmony_ci	 * activated. We have to keep up with the incoming data pace to
5788c2ecf20Sopenharmony_ci	 * prevent the Rx FIFO overflow causing the inbound data loss.
5798c2ecf20Sopenharmony_ci	 */
5808c2ecf20Sopenharmony_ci	len = dws->rx_len;
5818c2ecf20Sopenharmony_ci	buf = dws->rx;
5828c2ecf20Sopenharmony_ci	while (len) {
5838c2ecf20Sopenharmony_ci		entries = readl_relaxed(dws->regs + DW_SPI_RXFLR);
5848c2ecf20Sopenharmony_ci		if (!entries) {
5858c2ecf20Sopenharmony_ci			sts = readl_relaxed(dws->regs + DW_SPI_RISR);
5868c2ecf20Sopenharmony_ci			if (sts & SPI_INT_RXOI) {
5878c2ecf20Sopenharmony_ci				dev_err(&dws->master->dev, "FIFO overflow on Rx\n");
5888c2ecf20Sopenharmony_ci				return -EIO;
5898c2ecf20Sopenharmony_ci			}
5908c2ecf20Sopenharmony_ci			continue;
5918c2ecf20Sopenharmony_ci		}
5928c2ecf20Sopenharmony_ci		entries = min(entries, len);
5938c2ecf20Sopenharmony_ci		for (; entries; --entries, --len)
5948c2ecf20Sopenharmony_ci			*buf++ = dw_read_io_reg(dws, DW_SPI_DR);
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	return 0;
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_cistatic inline bool dw_spi_ctlr_busy(struct dw_spi *dws)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	return dw_readl(dws, DW_SPI_SR) & SR_BUSY;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_cistatic int dw_spi_wait_mem_op_done(struct dw_spi *dws)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	int retry = SPI_WAIT_RETRIES;
6088c2ecf20Sopenharmony_ci	struct spi_delay delay;
6098c2ecf20Sopenharmony_ci	unsigned long ns, us;
6108c2ecf20Sopenharmony_ci	u32 nents;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	nents = dw_readl(dws, DW_SPI_TXFLR);
6138c2ecf20Sopenharmony_ci	ns = NSEC_PER_SEC / dws->current_freq * nents;
6148c2ecf20Sopenharmony_ci	ns *= dws->n_bytes * BITS_PER_BYTE;
6158c2ecf20Sopenharmony_ci	if (ns <= NSEC_PER_USEC) {
6168c2ecf20Sopenharmony_ci		delay.unit = SPI_DELAY_UNIT_NSECS;
6178c2ecf20Sopenharmony_ci		delay.value = ns;
6188c2ecf20Sopenharmony_ci	} else {
6198c2ecf20Sopenharmony_ci		us = DIV_ROUND_UP(ns, NSEC_PER_USEC);
6208c2ecf20Sopenharmony_ci		delay.unit = SPI_DELAY_UNIT_USECS;
6218c2ecf20Sopenharmony_ci		delay.value = clamp_val(us, 0, USHRT_MAX);
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	while (dw_spi_ctlr_busy(dws) && retry--)
6258c2ecf20Sopenharmony_ci		spi_delay_exec(&delay, NULL);
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci	if (retry < 0) {
6288c2ecf20Sopenharmony_ci		dev_err(&dws->master->dev, "Mem op hanged up\n");
6298c2ecf20Sopenharmony_ci		return -EIO;
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	return 0;
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic void dw_spi_stop_mem_op(struct dw_spi *dws, struct spi_device *spi)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	spi_enable_chip(dws, 0);
6388c2ecf20Sopenharmony_ci	dw_spi_set_cs(spi, true);
6398c2ecf20Sopenharmony_ci	spi_enable_chip(dws, 1);
6408c2ecf20Sopenharmony_ci}
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci/*
6438c2ecf20Sopenharmony_ci * The SPI memory operation implementation below is the best choice for the
6448c2ecf20Sopenharmony_ci * devices, which are selected by the native chip-select lane. It's
6458c2ecf20Sopenharmony_ci * specifically developed to workaround the problem with automatic chip-select
6468c2ecf20Sopenharmony_ci * lane toggle when there is no data in the Tx FIFO buffer. Luckily the current
6478c2ecf20Sopenharmony_ci * SPI-mem core calls exec_op() callback only if the GPIO-based CS is
6488c2ecf20Sopenharmony_ci * unavailable.
6498c2ecf20Sopenharmony_ci */
6508c2ecf20Sopenharmony_cistatic int dw_spi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	struct dw_spi *dws = spi_controller_get_devdata(mem->spi->controller);
6538c2ecf20Sopenharmony_ci	struct dw_spi_cfg cfg;
6548c2ecf20Sopenharmony_ci	unsigned long flags;
6558c2ecf20Sopenharmony_ci	int ret;
6568c2ecf20Sopenharmony_ci
6578c2ecf20Sopenharmony_ci	/*
6588c2ecf20Sopenharmony_ci	 * Collect the outbound data into a single buffer to speed the
6598c2ecf20Sopenharmony_ci	 * transmission up at least on the initial stage.
6608c2ecf20Sopenharmony_ci	 */
6618c2ecf20Sopenharmony_ci	ret = dw_spi_init_mem_buf(dws, op);
6628c2ecf20Sopenharmony_ci	if (ret)
6638c2ecf20Sopenharmony_ci		return ret;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	/*
6668c2ecf20Sopenharmony_ci	 * DW SPI EEPROM-read mode is required only for the SPI memory Data-IN
6678c2ecf20Sopenharmony_ci	 * operation. Transmit-only mode is suitable for the rest of them.
6688c2ecf20Sopenharmony_ci	 */
6698c2ecf20Sopenharmony_ci	cfg.dfs = 8;
6708c2ecf20Sopenharmony_ci	cfg.freq = clamp(mem->spi->max_speed_hz, 0U, dws->max_mem_freq);
6718c2ecf20Sopenharmony_ci	if (op->data.dir == SPI_MEM_DATA_IN) {
6728c2ecf20Sopenharmony_ci		cfg.tmode = SPI_TMOD_EPROMREAD;
6738c2ecf20Sopenharmony_ci		cfg.ndf = op->data.nbytes;
6748c2ecf20Sopenharmony_ci	} else {
6758c2ecf20Sopenharmony_ci		cfg.tmode = SPI_TMOD_TO;
6768c2ecf20Sopenharmony_ci	}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	spi_enable_chip(dws, 0);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	dw_spi_update_config(dws, mem->spi, &cfg);
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ci	spi_mask_intr(dws, 0xff);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	spi_enable_chip(dws, 1);
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	/*
6878c2ecf20Sopenharmony_ci	 * DW APB SSI controller has very nasty peculiarities. First originally
6888c2ecf20Sopenharmony_ci	 * (without any vendor-specific modifications) it doesn't provide a
6898c2ecf20Sopenharmony_ci	 * direct way to set and clear the native chip-select signal. Instead
6908c2ecf20Sopenharmony_ci	 * the controller asserts the CS lane if Tx FIFO isn't empty and a
6918c2ecf20Sopenharmony_ci	 * transmission is going on, and automatically de-asserts it back to
6928c2ecf20Sopenharmony_ci	 * the high level if the Tx FIFO doesn't have anything to be pushed
6938c2ecf20Sopenharmony_ci	 * out. Due to that a multi-tasking or heavy IRQs activity might be
6948c2ecf20Sopenharmony_ci	 * fatal, since the transfer procedure preemption may cause the Tx FIFO
6958c2ecf20Sopenharmony_ci	 * getting empty and sudden CS de-assertion, which in the middle of the
6968c2ecf20Sopenharmony_ci	 * transfer will most likely cause the data loss. Secondly the
6978c2ecf20Sopenharmony_ci	 * EEPROM-read or Read-only DW SPI transfer modes imply the incoming
6988c2ecf20Sopenharmony_ci	 * data being automatically pulled in into the Rx FIFO. So if the
6998c2ecf20Sopenharmony_ci	 * driver software is late in fetching the data from the FIFO before
7008c2ecf20Sopenharmony_ci	 * it's overflown, new incoming data will be lost. In order to make
7018c2ecf20Sopenharmony_ci	 * sure the executed memory operations are CS-atomic and to prevent the
7028c2ecf20Sopenharmony_ci	 * Rx FIFO overflow we have to disable the local interrupts so to block
7038c2ecf20Sopenharmony_ci	 * any preemption during the subsequent IO operations.
7048c2ecf20Sopenharmony_ci	 *
7058c2ecf20Sopenharmony_ci	 * Note. At some circumstances disabling IRQs may not help to prevent
7068c2ecf20Sopenharmony_ci	 * the problems described above. The CS de-assertion and Rx FIFO
7078c2ecf20Sopenharmony_ci	 * overflow may still happen due to the relatively slow system bus or
7088c2ecf20Sopenharmony_ci	 * CPU not working fast enough, so the write-then-read algo implemented
7098c2ecf20Sopenharmony_ci	 * here just won't keep up with the SPI bus data transfer. Such
7108c2ecf20Sopenharmony_ci	 * situation is highly platform specific and is supposed to be fixed by
7118c2ecf20Sopenharmony_ci	 * manually restricting the SPI bus frequency using the
7128c2ecf20Sopenharmony_ci	 * dws->max_mem_freq parameter.
7138c2ecf20Sopenharmony_ci	 */
7148c2ecf20Sopenharmony_ci	local_irq_save(flags);
7158c2ecf20Sopenharmony_ci	preempt_disable();
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	ret = dw_spi_write_then_read(dws, mem->spi);
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	local_irq_restore(flags);
7208c2ecf20Sopenharmony_ci	preempt_enable();
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_ci	/*
7238c2ecf20Sopenharmony_ci	 * Wait for the operation being finished and check the controller
7248c2ecf20Sopenharmony_ci	 * status only if there hasn't been any run-time error detected. In the
7258c2ecf20Sopenharmony_ci	 * former case it's just pointless. In the later one to prevent an
7268c2ecf20Sopenharmony_ci	 * additional error message printing since any hw error flag being set
7278c2ecf20Sopenharmony_ci	 * would be due to an error detected on the data transfer.
7288c2ecf20Sopenharmony_ci	 */
7298c2ecf20Sopenharmony_ci	if (!ret) {
7308c2ecf20Sopenharmony_ci		ret = dw_spi_wait_mem_op_done(dws);
7318c2ecf20Sopenharmony_ci		if (!ret)
7328c2ecf20Sopenharmony_ci			ret = dw_spi_check_status(dws, true);
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	dw_spi_stop_mem_op(dws, mem->spi);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	dw_spi_free_mem_buf(dws);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return ret;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci/*
7438c2ecf20Sopenharmony_ci * Initialize the default memory operations if a glue layer hasn't specified
7448c2ecf20Sopenharmony_ci * custom ones. Direct mapping operations will be preserved anyway since DW SPI
7458c2ecf20Sopenharmony_ci * controller doesn't have an embedded dirmap interface. Note the memory
7468c2ecf20Sopenharmony_ci * operations implemented in this driver is the best choice only for the DW APB
7478c2ecf20Sopenharmony_ci * SSI controller with standard native CS functionality. If a hardware vendor
7488c2ecf20Sopenharmony_ci * has fixed the automatic CS assertion/de-assertion peculiarity, then it will
7498c2ecf20Sopenharmony_ci * be safer to use the normal SPI-messages-based transfers implementation.
7508c2ecf20Sopenharmony_ci */
7518c2ecf20Sopenharmony_cistatic void dw_spi_init_mem_ops(struct dw_spi *dws)
7528c2ecf20Sopenharmony_ci{
7538c2ecf20Sopenharmony_ci	if (!dws->mem_ops.exec_op && !(dws->caps & DW_SPI_CAP_CS_OVERRIDE) &&
7548c2ecf20Sopenharmony_ci	    !dws->set_cs) {
7558c2ecf20Sopenharmony_ci		dws->mem_ops.adjust_op_size = dw_spi_adjust_mem_op_size;
7568c2ecf20Sopenharmony_ci		dws->mem_ops.supports_op = dw_spi_supports_mem_op;
7578c2ecf20Sopenharmony_ci		dws->mem_ops.exec_op = dw_spi_exec_mem_op;
7588c2ecf20Sopenharmony_ci		if (!dws->max_mem_freq)
7598c2ecf20Sopenharmony_ci			dws->max_mem_freq = dws->max_freq;
7608c2ecf20Sopenharmony_ci	}
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci/* This may be called twice for each spi dev */
7648c2ecf20Sopenharmony_cistatic int dw_spi_setup(struct spi_device *spi)
7658c2ecf20Sopenharmony_ci{
7668c2ecf20Sopenharmony_ci	struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
7678c2ecf20Sopenharmony_ci	struct chip_data *chip;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	/* Only alloc on first setup */
7708c2ecf20Sopenharmony_ci	chip = spi_get_ctldata(spi);
7718c2ecf20Sopenharmony_ci	if (!chip) {
7728c2ecf20Sopenharmony_ci		struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
7738c2ecf20Sopenharmony_ci		u32 rx_sample_dly_ns;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
7768c2ecf20Sopenharmony_ci		if (!chip)
7778c2ecf20Sopenharmony_ci			return -ENOMEM;
7788c2ecf20Sopenharmony_ci		spi_set_ctldata(spi, chip);
7798c2ecf20Sopenharmony_ci		/* Get specific / default rx-sample-delay */
7808c2ecf20Sopenharmony_ci		if (device_property_read_u32(&spi->dev,
7818c2ecf20Sopenharmony_ci					     "rx-sample-delay-ns",
7828c2ecf20Sopenharmony_ci					     &rx_sample_dly_ns) != 0)
7838c2ecf20Sopenharmony_ci			/* Use default controller value */
7848c2ecf20Sopenharmony_ci			rx_sample_dly_ns = dws->def_rx_sample_dly_ns;
7858c2ecf20Sopenharmony_ci		chip->rx_sample_dly = DIV_ROUND_CLOSEST(rx_sample_dly_ns,
7868c2ecf20Sopenharmony_ci							NSEC_PER_SEC /
7878c2ecf20Sopenharmony_ci							dws->max_freq);
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	/*
7918c2ecf20Sopenharmony_ci	 * Update CR0 data each time the setup callback is invoked since
7928c2ecf20Sopenharmony_ci	 * the device parameters could have been changed, for instance, by
7938c2ecf20Sopenharmony_ci	 * the MMC SPI driver or something else.
7948c2ecf20Sopenharmony_ci	 */
7958c2ecf20Sopenharmony_ci	chip->cr0 = dw_spi_prepare_cr0(dws, spi);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	return 0;
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_cistatic void dw_spi_cleanup(struct spi_device *spi)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct chip_data *chip = spi_get_ctldata(spi);
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_ci	kfree(chip);
8058c2ecf20Sopenharmony_ci	spi_set_ctldata(spi, NULL);
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci/* Restart the controller, disable all interrupts, clean rx fifo */
8098c2ecf20Sopenharmony_cistatic void spi_hw_init(struct device *dev, struct dw_spi *dws)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	spi_reset_chip(dws);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	/*
8148c2ecf20Sopenharmony_ci	 * Try to detect the FIFO depth if not set by interface driver,
8158c2ecf20Sopenharmony_ci	 * the depth could be from 2 to 256 from HW spec
8168c2ecf20Sopenharmony_ci	 */
8178c2ecf20Sopenharmony_ci	if (!dws->fifo_len) {
8188c2ecf20Sopenharmony_ci		u32 fifo;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci		for (fifo = 1; fifo < 256; fifo++) {
8218c2ecf20Sopenharmony_ci			dw_writel(dws, DW_SPI_TXFTLR, fifo);
8228c2ecf20Sopenharmony_ci			if (fifo != dw_readl(dws, DW_SPI_TXFTLR))
8238c2ecf20Sopenharmony_ci				break;
8248c2ecf20Sopenharmony_ci		}
8258c2ecf20Sopenharmony_ci		dw_writel(dws, DW_SPI_TXFTLR, 0);
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci		dws->fifo_len = (fifo == 1) ? 0 : fifo;
8288c2ecf20Sopenharmony_ci		dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	/* enable HW fixup for explicit CS deselect for Amazon's alpine chip */
8328c2ecf20Sopenharmony_ci	if (dws->caps & DW_SPI_CAP_CS_OVERRIDE)
8338c2ecf20Sopenharmony_ci		dw_writel(dws, DW_SPI_CS_OVERRIDE, 0xF);
8348c2ecf20Sopenharmony_ci}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ciint dw_spi_add_host(struct device *dev, struct dw_spi *dws)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	struct spi_controller *master;
8398c2ecf20Sopenharmony_ci	int ret;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	if (!dws)
8428c2ecf20Sopenharmony_ci		return -EINVAL;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	master = spi_alloc_master(dev, 0);
8458c2ecf20Sopenharmony_ci	if (!master)
8468c2ecf20Sopenharmony_ci		return -ENOMEM;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	dws->master = master;
8498c2ecf20Sopenharmony_ci	dws->dma_addr = (dma_addr_t)(dws->paddr + DW_SPI_DR);
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	spi_controller_set_devdata(master, dws);
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	/* Basic HW init */
8548c2ecf20Sopenharmony_ci	spi_hw_init(dev, dws);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci	ret = request_irq(dws->irq, dw_spi_irq, IRQF_SHARED, dev_name(dev),
8578c2ecf20Sopenharmony_ci			  master);
8588c2ecf20Sopenharmony_ci	if (ret < 0 && ret != -ENOTCONN) {
8598c2ecf20Sopenharmony_ci		dev_err(dev, "can not get IRQ\n");
8608c2ecf20Sopenharmony_ci		goto err_free_master;
8618c2ecf20Sopenharmony_ci	}
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	dw_spi_init_mem_ops(dws);
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	master->use_gpio_descriptors = true;
8668c2ecf20Sopenharmony_ci	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LOOP;
8678c2ecf20Sopenharmony_ci	master->bits_per_word_mask =  SPI_BPW_RANGE_MASK(4, 16);
8688c2ecf20Sopenharmony_ci	master->bus_num = dws->bus_num;
8698c2ecf20Sopenharmony_ci	master->num_chipselect = dws->num_cs;
8708c2ecf20Sopenharmony_ci	master->setup = dw_spi_setup;
8718c2ecf20Sopenharmony_ci	master->cleanup = dw_spi_cleanup;
8728c2ecf20Sopenharmony_ci	if (dws->set_cs)
8738c2ecf20Sopenharmony_ci		master->set_cs = dws->set_cs;
8748c2ecf20Sopenharmony_ci	else
8758c2ecf20Sopenharmony_ci		master->set_cs = dw_spi_set_cs;
8768c2ecf20Sopenharmony_ci	master->transfer_one = dw_spi_transfer_one;
8778c2ecf20Sopenharmony_ci	master->handle_err = dw_spi_handle_err;
8788c2ecf20Sopenharmony_ci	if (dws->mem_ops.exec_op)
8798c2ecf20Sopenharmony_ci		master->mem_ops = &dws->mem_ops;
8808c2ecf20Sopenharmony_ci	master->max_speed_hz = dws->max_freq;
8818c2ecf20Sopenharmony_ci	master->dev.of_node = dev->of_node;
8828c2ecf20Sopenharmony_ci	master->dev.fwnode = dev->fwnode;
8838c2ecf20Sopenharmony_ci	master->flags = SPI_MASTER_GPIO_SS;
8848c2ecf20Sopenharmony_ci	master->auto_runtime_pm = true;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	/* Get default rx sample delay */
8878c2ecf20Sopenharmony_ci	device_property_read_u32(dev, "rx-sample-delay-ns",
8888c2ecf20Sopenharmony_ci				 &dws->def_rx_sample_dly_ns);
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	if (dws->dma_ops && dws->dma_ops->dma_init) {
8918c2ecf20Sopenharmony_ci		ret = dws->dma_ops->dma_init(dev, dws);
8928c2ecf20Sopenharmony_ci		if (ret) {
8938c2ecf20Sopenharmony_ci			dev_warn(dev, "DMA init failed\n");
8948c2ecf20Sopenharmony_ci		} else {
8958c2ecf20Sopenharmony_ci			master->can_dma = dws->dma_ops->can_dma;
8968c2ecf20Sopenharmony_ci			master->flags |= SPI_CONTROLLER_MUST_TX;
8978c2ecf20Sopenharmony_ci		}
8988c2ecf20Sopenharmony_ci	}
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	ret = spi_register_controller(master);
9018c2ecf20Sopenharmony_ci	if (ret) {
9028c2ecf20Sopenharmony_ci		dev_err(&master->dev, "problem registering spi master\n");
9038c2ecf20Sopenharmony_ci		goto err_dma_exit;
9048c2ecf20Sopenharmony_ci	}
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	dw_spi_debugfs_init(dws);
9078c2ecf20Sopenharmony_ci	return 0;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_cierr_dma_exit:
9108c2ecf20Sopenharmony_ci	if (dws->dma_ops && dws->dma_ops->dma_exit)
9118c2ecf20Sopenharmony_ci		dws->dma_ops->dma_exit(dws);
9128c2ecf20Sopenharmony_ci	spi_enable_chip(dws, 0);
9138c2ecf20Sopenharmony_ci	free_irq(dws->irq, master);
9148c2ecf20Sopenharmony_cierr_free_master:
9158c2ecf20Sopenharmony_ci	spi_controller_put(master);
9168c2ecf20Sopenharmony_ci	return ret;
9178c2ecf20Sopenharmony_ci}
9188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_spi_add_host);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_civoid dw_spi_remove_host(struct dw_spi *dws)
9218c2ecf20Sopenharmony_ci{
9228c2ecf20Sopenharmony_ci	dw_spi_debugfs_remove(dws);
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci	spi_unregister_controller(dws->master);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	if (dws->dma_ops && dws->dma_ops->dma_exit)
9278c2ecf20Sopenharmony_ci		dws->dma_ops->dma_exit(dws);
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	spi_shutdown_chip(dws);
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	free_irq(dws->irq, dws->master);
9328c2ecf20Sopenharmony_ci}
9338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_spi_remove_host);
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ciint dw_spi_suspend_host(struct dw_spi *dws)
9368c2ecf20Sopenharmony_ci{
9378c2ecf20Sopenharmony_ci	int ret;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	ret = spi_controller_suspend(dws->master);
9408c2ecf20Sopenharmony_ci	if (ret)
9418c2ecf20Sopenharmony_ci		return ret;
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	spi_shutdown_chip(dws);
9448c2ecf20Sopenharmony_ci	return 0;
9458c2ecf20Sopenharmony_ci}
9468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_spi_suspend_host);
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ciint dw_spi_resume_host(struct dw_spi *dws)
9498c2ecf20Sopenharmony_ci{
9508c2ecf20Sopenharmony_ci	spi_hw_init(&dws->master->dev, dws);
9518c2ecf20Sopenharmony_ci	return spi_controller_resume(dws->master);
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(dw_spi_resume_host);
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
9568c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for DesignWare SPI controller core");
9578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
958