162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// HiSilicon SPI Controller Driver for Kunpeng SoCs 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (c) 2021 HiSilicon Technologies Co., Ltd. 662306a36Sopenharmony_ci// Author: Jay Fang <f.fangjian@huawei.com> 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// This code is based on spi-dw-core.c. 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/acpi.h> 1162306a36Sopenharmony_ci#include <linux/bitfield.h> 1262306a36Sopenharmony_ci#include <linux/debugfs.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/property.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/spi/spi.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* Register offsets */ 2362306a36Sopenharmony_ci#define HISI_SPI_CSCR 0x00 /* cs control register */ 2462306a36Sopenharmony_ci#define HISI_SPI_CR 0x04 /* spi common control register */ 2562306a36Sopenharmony_ci#define HISI_SPI_ENR 0x08 /* spi enable register */ 2662306a36Sopenharmony_ci#define HISI_SPI_FIFOC 0x0c /* fifo level control register */ 2762306a36Sopenharmony_ci#define HISI_SPI_IMR 0x10 /* interrupt mask register */ 2862306a36Sopenharmony_ci#define HISI_SPI_DIN 0x14 /* data in register */ 2962306a36Sopenharmony_ci#define HISI_SPI_DOUT 0x18 /* data out register */ 3062306a36Sopenharmony_ci#define HISI_SPI_SR 0x1c /* status register */ 3162306a36Sopenharmony_ci#define HISI_SPI_RISR 0x20 /* raw interrupt status register */ 3262306a36Sopenharmony_ci#define HISI_SPI_ISR 0x24 /* interrupt status register */ 3362306a36Sopenharmony_ci#define HISI_SPI_ICR 0x28 /* interrupt clear register */ 3462306a36Sopenharmony_ci#define HISI_SPI_VERSION 0xe0 /* version register */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* Bit fields in HISI_SPI_CR */ 3762306a36Sopenharmony_ci#define CR_LOOP_MASK GENMASK(1, 1) 3862306a36Sopenharmony_ci#define CR_CPOL_MASK GENMASK(2, 2) 3962306a36Sopenharmony_ci#define CR_CPHA_MASK GENMASK(3, 3) 4062306a36Sopenharmony_ci#define CR_DIV_PRE_MASK GENMASK(11, 4) 4162306a36Sopenharmony_ci#define CR_DIV_POST_MASK GENMASK(19, 12) 4262306a36Sopenharmony_ci#define CR_BPW_MASK GENMASK(24, 20) 4362306a36Sopenharmony_ci#define CR_SPD_MODE_MASK GENMASK(25, 25) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Bit fields in HISI_SPI_FIFOC */ 4662306a36Sopenharmony_ci#define FIFOC_TX_MASK GENMASK(5, 3) 4762306a36Sopenharmony_ci#define FIFOC_RX_MASK GENMASK(11, 9) 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* Bit fields in HISI_SPI_IMR, 4 bits */ 5062306a36Sopenharmony_ci#define IMR_RXOF BIT(0) /* Receive Overflow */ 5162306a36Sopenharmony_ci#define IMR_RXTO BIT(1) /* Receive Timeout */ 5262306a36Sopenharmony_ci#define IMR_RX BIT(2) /* Receive */ 5362306a36Sopenharmony_ci#define IMR_TX BIT(3) /* Transmit */ 5462306a36Sopenharmony_ci#define IMR_MASK (IMR_RXOF | IMR_RXTO | IMR_RX | IMR_TX) 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* Bit fields in HISI_SPI_SR, 5 bits */ 5762306a36Sopenharmony_ci#define SR_TXE BIT(0) /* Transmit FIFO empty */ 5862306a36Sopenharmony_ci#define SR_TXNF BIT(1) /* Transmit FIFO not full */ 5962306a36Sopenharmony_ci#define SR_RXNE BIT(2) /* Receive FIFO not empty */ 6062306a36Sopenharmony_ci#define SR_RXF BIT(3) /* Receive FIFO full */ 6162306a36Sopenharmony_ci#define SR_BUSY BIT(4) /* Busy Flag */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* Bit fields in HISI_SPI_ISR, 4 bits */ 6462306a36Sopenharmony_ci#define ISR_RXOF BIT(0) /* Receive Overflow */ 6562306a36Sopenharmony_ci#define ISR_RXTO BIT(1) /* Receive Timeout */ 6662306a36Sopenharmony_ci#define ISR_RX BIT(2) /* Receive */ 6762306a36Sopenharmony_ci#define ISR_TX BIT(3) /* Transmit */ 6862306a36Sopenharmony_ci#define ISR_MASK (ISR_RXOF | ISR_RXTO | ISR_RX | ISR_TX) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* Bit fields in HISI_SPI_ICR, 2 bits */ 7162306a36Sopenharmony_ci#define ICR_RXOF BIT(0) /* Receive Overflow */ 7262306a36Sopenharmony_ci#define ICR_RXTO BIT(1) /* Receive Timeout */ 7362306a36Sopenharmony_ci#define ICR_MASK (ICR_RXOF | ICR_RXTO) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci#define DIV_POST_MAX 0xFF 7662306a36Sopenharmony_ci#define DIV_POST_MIN 0x00 7762306a36Sopenharmony_ci#define DIV_PRE_MAX 0xFE 7862306a36Sopenharmony_ci#define DIV_PRE_MIN 0x02 7962306a36Sopenharmony_ci#define CLK_DIV_MAX ((1 + DIV_POST_MAX) * DIV_PRE_MAX) 8062306a36Sopenharmony_ci#define CLK_DIV_MIN ((1 + DIV_POST_MIN) * DIV_PRE_MIN) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define DEFAULT_NUM_CS 1 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci#define HISI_SPI_WAIT_TIMEOUT_MS 10UL 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cienum hisi_spi_rx_level_trig { 8762306a36Sopenharmony_ci HISI_SPI_RX_1, 8862306a36Sopenharmony_ci HISI_SPI_RX_4, 8962306a36Sopenharmony_ci HISI_SPI_RX_8, 9062306a36Sopenharmony_ci HISI_SPI_RX_16, 9162306a36Sopenharmony_ci HISI_SPI_RX_32, 9262306a36Sopenharmony_ci HISI_SPI_RX_64, 9362306a36Sopenharmony_ci HISI_SPI_RX_128 9462306a36Sopenharmony_ci}; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cienum hisi_spi_tx_level_trig { 9762306a36Sopenharmony_ci HISI_SPI_TX_1_OR_LESS, 9862306a36Sopenharmony_ci HISI_SPI_TX_4_OR_LESS, 9962306a36Sopenharmony_ci HISI_SPI_TX_8_OR_LESS, 10062306a36Sopenharmony_ci HISI_SPI_TX_16_OR_LESS, 10162306a36Sopenharmony_ci HISI_SPI_TX_32_OR_LESS, 10262306a36Sopenharmony_ci HISI_SPI_TX_64_OR_LESS, 10362306a36Sopenharmony_ci HISI_SPI_TX_128_OR_LESS 10462306a36Sopenharmony_ci}; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cienum hisi_spi_frame_n_bytes { 10762306a36Sopenharmony_ci HISI_SPI_N_BYTES_NULL, 10862306a36Sopenharmony_ci HISI_SPI_N_BYTES_U8, 10962306a36Sopenharmony_ci HISI_SPI_N_BYTES_U16, 11062306a36Sopenharmony_ci HISI_SPI_N_BYTES_U32 = 4 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* Slave spi_dev related */ 11462306a36Sopenharmony_cistruct hisi_chip_data { 11562306a36Sopenharmony_ci u32 cr; 11662306a36Sopenharmony_ci u32 speed_hz; /* baud rate */ 11762306a36Sopenharmony_ci u16 clk_div; /* baud rate divider */ 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci /* clk_div = (1 + div_post) * div_pre */ 12062306a36Sopenharmony_ci u8 div_post; /* value from 0 to 255 */ 12162306a36Sopenharmony_ci u8 div_pre; /* value from 2 to 254 (even only!) */ 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct hisi_spi { 12562306a36Sopenharmony_ci struct device *dev; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci void __iomem *regs; 12862306a36Sopenharmony_ci int irq; 12962306a36Sopenharmony_ci u32 fifo_len; /* depth of the FIFO buffer */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Current message transfer state info */ 13262306a36Sopenharmony_ci const void *tx; 13362306a36Sopenharmony_ci unsigned int tx_len; 13462306a36Sopenharmony_ci void *rx; 13562306a36Sopenharmony_ci unsigned int rx_len; 13662306a36Sopenharmony_ci u8 n_bytes; /* current is a 1/2/4 bytes op */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci struct dentry *debugfs; 13962306a36Sopenharmony_ci struct debugfs_regset32 regset; 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#define HISI_SPI_DBGFS_REG(_name, _off) \ 14362306a36Sopenharmony_ci{ \ 14462306a36Sopenharmony_ci .name = _name, \ 14562306a36Sopenharmony_ci .offset = _off, \ 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic const struct debugfs_reg32 hisi_spi_regs[] = { 14962306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("CSCR", HISI_SPI_CSCR), 15062306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("CR", HISI_SPI_CR), 15162306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("ENR", HISI_SPI_ENR), 15262306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("FIFOC", HISI_SPI_FIFOC), 15362306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("IMR", HISI_SPI_IMR), 15462306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("DIN", HISI_SPI_DIN), 15562306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("DOUT", HISI_SPI_DOUT), 15662306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("SR", HISI_SPI_SR), 15762306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("RISR", HISI_SPI_RISR), 15862306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("ISR", HISI_SPI_ISR), 15962306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("ICR", HISI_SPI_ICR), 16062306a36Sopenharmony_ci HISI_SPI_DBGFS_REG("VERSION", HISI_SPI_VERSION), 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistatic int hisi_spi_debugfs_init(struct hisi_spi *hs) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci char name[32]; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci struct spi_controller *host; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci host = container_of(hs->dev, struct spi_controller, dev); 17062306a36Sopenharmony_ci snprintf(name, 32, "hisi_spi%d", host->bus_num); 17162306a36Sopenharmony_ci hs->debugfs = debugfs_create_dir(name, NULL); 17262306a36Sopenharmony_ci if (IS_ERR(hs->debugfs)) 17362306a36Sopenharmony_ci return -ENOMEM; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci hs->regset.regs = hisi_spi_regs; 17662306a36Sopenharmony_ci hs->regset.nregs = ARRAY_SIZE(hisi_spi_regs); 17762306a36Sopenharmony_ci hs->regset.base = hs->regs; 17862306a36Sopenharmony_ci debugfs_create_regset32("registers", 0400, hs->debugfs, &hs->regset); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic u32 hisi_spi_busy(struct hisi_spi *hs) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci return readl(hs->regs + HISI_SPI_SR) & SR_BUSY; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic u32 hisi_spi_rx_not_empty(struct hisi_spi *hs) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci return readl(hs->regs + HISI_SPI_SR) & SR_RXNE; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic u32 hisi_spi_tx_not_full(struct hisi_spi *hs) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci return readl(hs->regs + HISI_SPI_SR) & SR_TXNF; 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic void hisi_spi_flush_fifo(struct hisi_spi *hs) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci unsigned long limit = loops_per_jiffy << 1; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci do { 20362306a36Sopenharmony_ci while (hisi_spi_rx_not_empty(hs)) 20462306a36Sopenharmony_ci readl(hs->regs + HISI_SPI_DOUT); 20562306a36Sopenharmony_ci } while (hisi_spi_busy(hs) && limit--); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/* Disable the controller and all interrupts */ 20962306a36Sopenharmony_cistatic void hisi_spi_disable(struct hisi_spi *hs) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci writel(0, hs->regs + HISI_SPI_ENR); 21262306a36Sopenharmony_ci writel(IMR_MASK, hs->regs + HISI_SPI_IMR); 21362306a36Sopenharmony_ci writel(ICR_MASK, hs->regs + HISI_SPI_ICR); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic u8 hisi_spi_n_bytes(struct spi_transfer *transfer) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci if (transfer->bits_per_word <= 8) 21962306a36Sopenharmony_ci return HISI_SPI_N_BYTES_U8; 22062306a36Sopenharmony_ci else if (transfer->bits_per_word <= 16) 22162306a36Sopenharmony_ci return HISI_SPI_N_BYTES_U16; 22262306a36Sopenharmony_ci else 22362306a36Sopenharmony_ci return HISI_SPI_N_BYTES_U32; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic void hisi_spi_reader(struct hisi_spi *hs) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci u32 max = min_t(u32, hs->rx_len, hs->fifo_len); 22962306a36Sopenharmony_ci u32 rxw; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci while (hisi_spi_rx_not_empty(hs) && max--) { 23262306a36Sopenharmony_ci rxw = readl(hs->regs + HISI_SPI_DOUT); 23362306a36Sopenharmony_ci /* Check the transfer's original "rx" is not null */ 23462306a36Sopenharmony_ci if (hs->rx) { 23562306a36Sopenharmony_ci switch (hs->n_bytes) { 23662306a36Sopenharmony_ci case HISI_SPI_N_BYTES_U8: 23762306a36Sopenharmony_ci *(u8 *)(hs->rx) = rxw; 23862306a36Sopenharmony_ci break; 23962306a36Sopenharmony_ci case HISI_SPI_N_BYTES_U16: 24062306a36Sopenharmony_ci *(u16 *)(hs->rx) = rxw; 24162306a36Sopenharmony_ci break; 24262306a36Sopenharmony_ci case HISI_SPI_N_BYTES_U32: 24362306a36Sopenharmony_ci *(u32 *)(hs->rx) = rxw; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci hs->rx += hs->n_bytes; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci --hs->rx_len; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic void hisi_spi_writer(struct hisi_spi *hs) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci u32 max = min_t(u32, hs->tx_len, hs->fifo_len); 25562306a36Sopenharmony_ci u32 txw = 0; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci while (hisi_spi_tx_not_full(hs) && max--) { 25862306a36Sopenharmony_ci /* Check the transfer's original "tx" is not null */ 25962306a36Sopenharmony_ci if (hs->tx) { 26062306a36Sopenharmony_ci switch (hs->n_bytes) { 26162306a36Sopenharmony_ci case HISI_SPI_N_BYTES_U8: 26262306a36Sopenharmony_ci txw = *(u8 *)(hs->tx); 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci case HISI_SPI_N_BYTES_U16: 26562306a36Sopenharmony_ci txw = *(u16 *)(hs->tx); 26662306a36Sopenharmony_ci break; 26762306a36Sopenharmony_ci case HISI_SPI_N_BYTES_U32: 26862306a36Sopenharmony_ci txw = *(u32 *)(hs->tx); 26962306a36Sopenharmony_ci break; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci hs->tx += hs->n_bytes; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci writel(txw, hs->regs + HISI_SPI_DIN); 27462306a36Sopenharmony_ci --hs->tx_len; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void __hisi_calc_div_reg(struct hisi_chip_data *chip) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci chip->div_pre = DIV_PRE_MAX; 28162306a36Sopenharmony_ci while (chip->div_pre >= DIV_PRE_MIN) { 28262306a36Sopenharmony_ci if (chip->clk_div % chip->div_pre == 0) 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci chip->div_pre -= 2; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (chip->div_pre > chip->clk_div) 28962306a36Sopenharmony_ci chip->div_pre = chip->clk_div; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci chip->div_post = (chip->clk_div / chip->div_pre) - 1; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic u32 hisi_calc_effective_speed(struct spi_controller *host, 29562306a36Sopenharmony_ci struct hisi_chip_data *chip, u32 speed_hz) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci u32 effective_speed; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* Note clock divider doesn't support odd numbers */ 30062306a36Sopenharmony_ci chip->clk_div = DIV_ROUND_UP(host->max_speed_hz, speed_hz) + 1; 30162306a36Sopenharmony_ci chip->clk_div &= 0xfffe; 30262306a36Sopenharmony_ci if (chip->clk_div > CLK_DIV_MAX) 30362306a36Sopenharmony_ci chip->clk_div = CLK_DIV_MAX; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci effective_speed = host->max_speed_hz / chip->clk_div; 30662306a36Sopenharmony_ci if (chip->speed_hz != effective_speed) { 30762306a36Sopenharmony_ci __hisi_calc_div_reg(chip); 30862306a36Sopenharmony_ci chip->speed_hz = effective_speed; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return effective_speed; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic u32 hisi_spi_prepare_cr(struct spi_device *spi) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci u32 cr = FIELD_PREP(CR_SPD_MODE_MASK, 1); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci cr |= FIELD_PREP(CR_CPHA_MASK, (spi->mode & SPI_CPHA) ? 1 : 0); 31962306a36Sopenharmony_ci cr |= FIELD_PREP(CR_CPOL_MASK, (spi->mode & SPI_CPOL) ? 1 : 0); 32062306a36Sopenharmony_ci cr |= FIELD_PREP(CR_LOOP_MASK, (spi->mode & SPI_LOOP) ? 1 : 0); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return cr; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void hisi_spi_hw_init(struct hisi_spi *hs) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci hisi_spi_disable(hs); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* FIFO default config */ 33062306a36Sopenharmony_ci writel(FIELD_PREP(FIFOC_TX_MASK, HISI_SPI_TX_64_OR_LESS) | 33162306a36Sopenharmony_ci FIELD_PREP(FIFOC_RX_MASK, HISI_SPI_RX_16), 33262306a36Sopenharmony_ci hs->regs + HISI_SPI_FIFOC); 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci hs->fifo_len = 256; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic irqreturn_t hisi_spi_irq(int irq, void *dev_id) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct spi_controller *host = dev_id; 34062306a36Sopenharmony_ci struct hisi_spi *hs = spi_controller_get_devdata(host); 34162306a36Sopenharmony_ci u32 irq_status = readl(hs->regs + HISI_SPI_ISR) & ISR_MASK; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (!irq_status) 34462306a36Sopenharmony_ci return IRQ_NONE; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci if (!host->cur_msg) 34762306a36Sopenharmony_ci return IRQ_HANDLED; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Error handling */ 35062306a36Sopenharmony_ci if (irq_status & ISR_RXOF) { 35162306a36Sopenharmony_ci dev_err(hs->dev, "interrupt_transfer: fifo overflow\n"); 35262306a36Sopenharmony_ci host->cur_msg->status = -EIO; 35362306a36Sopenharmony_ci goto finalize_transfer; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci /* 35762306a36Sopenharmony_ci * Read data from the Rx FIFO every time. If there is 35862306a36Sopenharmony_ci * nothing left to receive, finalize the transfer. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci hisi_spi_reader(hs); 36162306a36Sopenharmony_ci if (!hs->rx_len) 36262306a36Sopenharmony_ci goto finalize_transfer; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* Send data out when Tx FIFO IRQ triggered */ 36562306a36Sopenharmony_ci if (irq_status & ISR_TX) 36662306a36Sopenharmony_ci hisi_spi_writer(hs); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return IRQ_HANDLED; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cifinalize_transfer: 37162306a36Sopenharmony_ci hisi_spi_disable(hs); 37262306a36Sopenharmony_ci spi_finalize_current_transfer(host); 37362306a36Sopenharmony_ci return IRQ_HANDLED; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int hisi_spi_transfer_one(struct spi_controller *host, 37762306a36Sopenharmony_ci struct spi_device *spi, struct spi_transfer *transfer) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct hisi_spi *hs = spi_controller_get_devdata(host); 38062306a36Sopenharmony_ci struct hisi_chip_data *chip = spi_get_ctldata(spi); 38162306a36Sopenharmony_ci u32 cr = chip->cr; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Update per transfer options for speed and bpw */ 38462306a36Sopenharmony_ci transfer->effective_speed_hz = 38562306a36Sopenharmony_ci hisi_calc_effective_speed(host, chip, transfer->speed_hz); 38662306a36Sopenharmony_ci cr |= FIELD_PREP(CR_DIV_PRE_MASK, chip->div_pre); 38762306a36Sopenharmony_ci cr |= FIELD_PREP(CR_DIV_POST_MASK, chip->div_post); 38862306a36Sopenharmony_ci cr |= FIELD_PREP(CR_BPW_MASK, transfer->bits_per_word - 1); 38962306a36Sopenharmony_ci writel(cr, hs->regs + HISI_SPI_CR); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci hisi_spi_flush_fifo(hs); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci hs->n_bytes = hisi_spi_n_bytes(transfer); 39462306a36Sopenharmony_ci hs->tx = transfer->tx_buf; 39562306a36Sopenharmony_ci hs->tx_len = transfer->len / hs->n_bytes; 39662306a36Sopenharmony_ci hs->rx = transfer->rx_buf; 39762306a36Sopenharmony_ci hs->rx_len = hs->tx_len; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* 40062306a36Sopenharmony_ci * Ensure that the transfer data above has been updated 40162306a36Sopenharmony_ci * before the interrupt to start. 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ci smp_mb(); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Enable all interrupts and the controller */ 40662306a36Sopenharmony_ci writel(~(u32)IMR_MASK, hs->regs + HISI_SPI_IMR); 40762306a36Sopenharmony_ci writel(1, hs->regs + HISI_SPI_ENR); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return 1; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic void hisi_spi_handle_err(struct spi_controller *host, 41362306a36Sopenharmony_ci struct spi_message *msg) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct hisi_spi *hs = spi_controller_get_devdata(host); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci hisi_spi_disable(hs); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* 42062306a36Sopenharmony_ci * Wait for interrupt handler that is 42162306a36Sopenharmony_ci * already in timeout to complete. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci msleep(HISI_SPI_WAIT_TIMEOUT_MS); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic int hisi_spi_setup(struct spi_device *spi) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct hisi_chip_data *chip; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci /* Only alloc on first setup */ 43162306a36Sopenharmony_ci chip = spi_get_ctldata(spi); 43262306a36Sopenharmony_ci if (!chip) { 43362306a36Sopenharmony_ci chip = kzalloc(sizeof(*chip), GFP_KERNEL); 43462306a36Sopenharmony_ci if (!chip) 43562306a36Sopenharmony_ci return -ENOMEM; 43662306a36Sopenharmony_ci spi_set_ctldata(spi, chip); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci chip->cr = hisi_spi_prepare_cr(spi); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci return 0; 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic void hisi_spi_cleanup(struct spi_device *spi) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct hisi_chip_data *chip = spi_get_ctldata(spi); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci kfree(chip); 44962306a36Sopenharmony_ci spi_set_ctldata(spi, NULL); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic int hisi_spi_probe(struct platform_device *pdev) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 45562306a36Sopenharmony_ci struct spi_controller *host; 45662306a36Sopenharmony_ci struct hisi_spi *hs; 45762306a36Sopenharmony_ci int ret, irq; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 46062306a36Sopenharmony_ci if (irq < 0) 46162306a36Sopenharmony_ci return irq; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci host = devm_spi_alloc_host(dev, sizeof(*hs)); 46462306a36Sopenharmony_ci if (!host) 46562306a36Sopenharmony_ci return -ENOMEM; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci platform_set_drvdata(pdev, host); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci hs = spi_controller_get_devdata(host); 47062306a36Sopenharmony_ci hs->dev = dev; 47162306a36Sopenharmony_ci hs->irq = irq; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci hs->regs = devm_platform_ioremap_resource(pdev, 0); 47462306a36Sopenharmony_ci if (IS_ERR(hs->regs)) 47562306a36Sopenharmony_ci return PTR_ERR(hs->regs); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* Specify maximum SPI clocking speed (host only) by firmware */ 47862306a36Sopenharmony_ci ret = device_property_read_u32(dev, "spi-max-frequency", 47962306a36Sopenharmony_ci &host->max_speed_hz); 48062306a36Sopenharmony_ci if (ret) { 48162306a36Sopenharmony_ci dev_err(dev, "failed to get max SPI clocking speed, ret=%d\n", 48262306a36Sopenharmony_ci ret); 48362306a36Sopenharmony_ci return -EINVAL; 48462306a36Sopenharmony_ci } 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci ret = device_property_read_u16(dev, "num-cs", 48762306a36Sopenharmony_ci &host->num_chipselect); 48862306a36Sopenharmony_ci if (ret) 48962306a36Sopenharmony_ci host->num_chipselect = DEFAULT_NUM_CS; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci host->use_gpio_descriptors = true; 49262306a36Sopenharmony_ci host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; 49362306a36Sopenharmony_ci host->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); 49462306a36Sopenharmony_ci host->bus_num = pdev->id; 49562306a36Sopenharmony_ci host->setup = hisi_spi_setup; 49662306a36Sopenharmony_ci host->cleanup = hisi_spi_cleanup; 49762306a36Sopenharmony_ci host->transfer_one = hisi_spi_transfer_one; 49862306a36Sopenharmony_ci host->handle_err = hisi_spi_handle_err; 49962306a36Sopenharmony_ci host->dev.fwnode = dev->fwnode; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci hisi_spi_hw_init(hs); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci ret = devm_request_irq(dev, hs->irq, hisi_spi_irq, 0, dev_name(dev), 50462306a36Sopenharmony_ci host); 50562306a36Sopenharmony_ci if (ret < 0) { 50662306a36Sopenharmony_ci dev_err(dev, "failed to get IRQ=%d, ret=%d\n", hs->irq, ret); 50762306a36Sopenharmony_ci return ret; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci ret = spi_register_controller(host); 51162306a36Sopenharmony_ci if (ret) { 51262306a36Sopenharmony_ci dev_err(dev, "failed to register spi host, ret=%d\n", ret); 51362306a36Sopenharmony_ci return ret; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (hisi_spi_debugfs_init(hs)) 51762306a36Sopenharmony_ci dev_info(dev, "failed to create debugfs dir\n"); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci dev_info(dev, "hw version:0x%x max-freq:%u kHz\n", 52062306a36Sopenharmony_ci readl(hs->regs + HISI_SPI_VERSION), 52162306a36Sopenharmony_ci host->max_speed_hz / 1000); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return 0; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic void hisi_spi_remove(struct platform_device *pdev) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci struct spi_controller *host = platform_get_drvdata(pdev); 52962306a36Sopenharmony_ci struct hisi_spi *hs = spi_controller_get_devdata(host); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci debugfs_remove_recursive(hs->debugfs); 53262306a36Sopenharmony_ci spi_unregister_controller(host); 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic const struct acpi_device_id hisi_spi_acpi_match[] = { 53662306a36Sopenharmony_ci {"HISI03E1", 0}, 53762306a36Sopenharmony_ci {} 53862306a36Sopenharmony_ci}; 53962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, hisi_spi_acpi_match); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic struct platform_driver hisi_spi_driver = { 54262306a36Sopenharmony_ci .probe = hisi_spi_probe, 54362306a36Sopenharmony_ci .remove_new = hisi_spi_remove, 54462306a36Sopenharmony_ci .driver = { 54562306a36Sopenharmony_ci .name = "hisi-kunpeng-spi", 54662306a36Sopenharmony_ci .acpi_match_table = hisi_spi_acpi_match, 54762306a36Sopenharmony_ci }, 54862306a36Sopenharmony_ci}; 54962306a36Sopenharmony_cimodule_platform_driver(hisi_spi_driver); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ciMODULE_AUTHOR("Jay Fang <f.fangjian@huawei.com>"); 55262306a36Sopenharmony_ciMODULE_DESCRIPTION("HiSilicon SPI Controller Driver for Kunpeng SoCs"); 55362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 554