162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011-2015 Daniel Schwierzeck <daniel.schwierzeck@gmail.com> 462306a36Sopenharmony_ci * Copyright (C) 2016 Hauke Mehrtens <hauke@hauke-m.de> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/of.h> 1062306a36Sopenharmony_ci#include <linux/platform_device.h> 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/io.h> 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/sched.h> 1662306a36Sopenharmony_ci#include <linux/completion.h> 1762306a36Sopenharmony_ci#include <linux/spinlock.h> 1862306a36Sopenharmony_ci#include <linux/err.h> 1962306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2062306a36Sopenharmony_ci#include <linux/spi/spi.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#ifdef CONFIG_LANTIQ 2362306a36Sopenharmony_ci#include <lantiq_soc.h> 2462306a36Sopenharmony_ci#endif 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define LTQ_SPI_RX_IRQ_NAME "spi_rx" 2762306a36Sopenharmony_ci#define LTQ_SPI_TX_IRQ_NAME "spi_tx" 2862306a36Sopenharmony_ci#define LTQ_SPI_ERR_IRQ_NAME "spi_err" 2962306a36Sopenharmony_ci#define LTQ_SPI_FRM_IRQ_NAME "spi_frm" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define LTQ_SPI_CLC 0x00 3262306a36Sopenharmony_ci#define LTQ_SPI_PISEL 0x04 3362306a36Sopenharmony_ci#define LTQ_SPI_ID 0x08 3462306a36Sopenharmony_ci#define LTQ_SPI_CON 0x10 3562306a36Sopenharmony_ci#define LTQ_SPI_STAT 0x14 3662306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE 0x18 3762306a36Sopenharmony_ci#define LTQ_SPI_TB 0x20 3862306a36Sopenharmony_ci#define LTQ_SPI_RB 0x24 3962306a36Sopenharmony_ci#define LTQ_SPI_RXFCON 0x30 4062306a36Sopenharmony_ci#define LTQ_SPI_TXFCON 0x34 4162306a36Sopenharmony_ci#define LTQ_SPI_FSTAT 0x38 4262306a36Sopenharmony_ci#define LTQ_SPI_BRT 0x40 4362306a36Sopenharmony_ci#define LTQ_SPI_BRSTAT 0x44 4462306a36Sopenharmony_ci#define LTQ_SPI_SFCON 0x60 4562306a36Sopenharmony_ci#define LTQ_SPI_SFSTAT 0x64 4662306a36Sopenharmony_ci#define LTQ_SPI_GPOCON 0x70 4762306a36Sopenharmony_ci#define LTQ_SPI_GPOSTAT 0x74 4862306a36Sopenharmony_ci#define LTQ_SPI_FPGO 0x78 4962306a36Sopenharmony_ci#define LTQ_SPI_RXREQ 0x80 5062306a36Sopenharmony_ci#define LTQ_SPI_RXCNT 0x84 5162306a36Sopenharmony_ci#define LTQ_SPI_DMACON 0xec 5262306a36Sopenharmony_ci#define LTQ_SPI_IRNEN 0xf4 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define LTQ_SPI_CLC_SMC_S 16 /* Clock divider for sleep mode */ 5562306a36Sopenharmony_ci#define LTQ_SPI_CLC_SMC_M (0xFF << LTQ_SPI_CLC_SMC_S) 5662306a36Sopenharmony_ci#define LTQ_SPI_CLC_RMC_S 8 /* Clock divider for normal run mode */ 5762306a36Sopenharmony_ci#define LTQ_SPI_CLC_RMC_M (0xFF << LTQ_SPI_CLC_RMC_S) 5862306a36Sopenharmony_ci#define LTQ_SPI_CLC_DISS BIT(1) /* Disable status bit */ 5962306a36Sopenharmony_ci#define LTQ_SPI_CLC_DISR BIT(0) /* Disable request bit */ 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define LTQ_SPI_ID_TXFS_S 24 /* Implemented TX FIFO size */ 6262306a36Sopenharmony_ci#define LTQ_SPI_ID_RXFS_S 16 /* Implemented RX FIFO size */ 6362306a36Sopenharmony_ci#define LTQ_SPI_ID_MOD_S 8 /* Module ID */ 6462306a36Sopenharmony_ci#define LTQ_SPI_ID_MOD_M (0xff << LTQ_SPI_ID_MOD_S) 6562306a36Sopenharmony_ci#define LTQ_SPI_ID_CFG_S 5 /* DMA interface support */ 6662306a36Sopenharmony_ci#define LTQ_SPI_ID_CFG_M (1 << LTQ_SPI_ID_CFG_S) 6762306a36Sopenharmony_ci#define LTQ_SPI_ID_REV_M 0x1F /* Hardware revision number */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define LTQ_SPI_CON_BM_S 16 /* Data width selection */ 7062306a36Sopenharmony_ci#define LTQ_SPI_CON_BM_M (0x1F << LTQ_SPI_CON_BM_S) 7162306a36Sopenharmony_ci#define LTQ_SPI_CON_EM BIT(24) /* Echo mode */ 7262306a36Sopenharmony_ci#define LTQ_SPI_CON_IDLE BIT(23) /* Idle bit value */ 7362306a36Sopenharmony_ci#define LTQ_SPI_CON_ENBV BIT(22) /* Enable byte valid control */ 7462306a36Sopenharmony_ci#define LTQ_SPI_CON_RUEN BIT(12) /* Receive underflow error enable */ 7562306a36Sopenharmony_ci#define LTQ_SPI_CON_TUEN BIT(11) /* Transmit underflow error enable */ 7662306a36Sopenharmony_ci#define LTQ_SPI_CON_AEN BIT(10) /* Abort error enable */ 7762306a36Sopenharmony_ci#define LTQ_SPI_CON_REN BIT(9) /* Receive overflow error enable */ 7862306a36Sopenharmony_ci#define LTQ_SPI_CON_TEN BIT(8) /* Transmit overflow error enable */ 7962306a36Sopenharmony_ci#define LTQ_SPI_CON_LB BIT(7) /* Loopback control */ 8062306a36Sopenharmony_ci#define LTQ_SPI_CON_PO BIT(6) /* Clock polarity control */ 8162306a36Sopenharmony_ci#define LTQ_SPI_CON_PH BIT(5) /* Clock phase control */ 8262306a36Sopenharmony_ci#define LTQ_SPI_CON_HB BIT(4) /* Heading control */ 8362306a36Sopenharmony_ci#define LTQ_SPI_CON_RXOFF BIT(1) /* Switch receiver off */ 8462306a36Sopenharmony_ci#define LTQ_SPI_CON_TXOFF BIT(0) /* Switch transmitter off */ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define LTQ_SPI_STAT_RXBV_S 28 8762306a36Sopenharmony_ci#define LTQ_SPI_STAT_RXBV_M (0x7 << LTQ_SPI_STAT_RXBV_S) 8862306a36Sopenharmony_ci#define LTQ_SPI_STAT_BSY BIT(13) /* Busy flag */ 8962306a36Sopenharmony_ci#define LTQ_SPI_STAT_RUE BIT(12) /* Receive underflow error flag */ 9062306a36Sopenharmony_ci#define LTQ_SPI_STAT_TUE BIT(11) /* Transmit underflow error flag */ 9162306a36Sopenharmony_ci#define LTQ_SPI_STAT_AE BIT(10) /* Abort error flag */ 9262306a36Sopenharmony_ci#define LTQ_SPI_STAT_RE BIT(9) /* Receive error flag */ 9362306a36Sopenharmony_ci#define LTQ_SPI_STAT_TE BIT(8) /* Transmit error flag */ 9462306a36Sopenharmony_ci#define LTQ_SPI_STAT_ME BIT(7) /* Mode error flag */ 9562306a36Sopenharmony_ci#define LTQ_SPI_STAT_MS BIT(1) /* Host/target select bit */ 9662306a36Sopenharmony_ci#define LTQ_SPI_STAT_EN BIT(0) /* Enable bit */ 9762306a36Sopenharmony_ci#define LTQ_SPI_STAT_ERRORS (LTQ_SPI_STAT_ME | LTQ_SPI_STAT_TE | \ 9862306a36Sopenharmony_ci LTQ_SPI_STAT_RE | LTQ_SPI_STAT_AE | \ 9962306a36Sopenharmony_ci LTQ_SPI_STAT_TUE | LTQ_SPI_STAT_RUE) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETTUE BIT(15) /* Set transmit underflow error flag */ 10262306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETAE BIT(14) /* Set abort error flag */ 10362306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETRE BIT(13) /* Set receive error flag */ 10462306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETTE BIT(12) /* Set transmit error flag */ 10562306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRTUE BIT(11) /* Clear transmit underflow error flag */ 10662306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRAE BIT(10) /* Clear abort error flag */ 10762306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRRE BIT(9) /* Clear receive error flag */ 10862306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRTE BIT(8) /* Clear transmit error flag */ 10962306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETME BIT(7) /* Set mode error flag */ 11062306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRME BIT(6) /* Clear mode error flag */ 11162306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETRUE BIT(5) /* Set receive underflow error flag */ 11262306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRRUE BIT(4) /* Clear receive underflow error flag */ 11362306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETMS BIT(3) /* Set host select bit */ 11462306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLRMS BIT(2) /* Clear host select bit */ 11562306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_SETEN BIT(1) /* Set enable bit (operational mode) */ 11662306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLREN BIT(0) /* Clear enable bit (config mode */ 11762306a36Sopenharmony_ci#define LTQ_SPI_WHBSTATE_CLR_ERRORS (LTQ_SPI_WHBSTATE_CLRRUE | \ 11862306a36Sopenharmony_ci LTQ_SPI_WHBSTATE_CLRME | \ 11962306a36Sopenharmony_ci LTQ_SPI_WHBSTATE_CLRTE | \ 12062306a36Sopenharmony_ci LTQ_SPI_WHBSTATE_CLRRE | \ 12162306a36Sopenharmony_ci LTQ_SPI_WHBSTATE_CLRAE | \ 12262306a36Sopenharmony_ci LTQ_SPI_WHBSTATE_CLRTUE) 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci#define LTQ_SPI_RXFCON_RXFITL_S 8 /* FIFO interrupt trigger level */ 12562306a36Sopenharmony_ci#define LTQ_SPI_RXFCON_RXFLU BIT(1) /* FIFO flush */ 12662306a36Sopenharmony_ci#define LTQ_SPI_RXFCON_RXFEN BIT(0) /* FIFO enable */ 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#define LTQ_SPI_TXFCON_TXFITL_S 8 /* FIFO interrupt trigger level */ 12962306a36Sopenharmony_ci#define LTQ_SPI_TXFCON_TXFLU BIT(1) /* FIFO flush */ 13062306a36Sopenharmony_ci#define LTQ_SPI_TXFCON_TXFEN BIT(0) /* FIFO enable */ 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci#define LTQ_SPI_FSTAT_RXFFL_S 0 13362306a36Sopenharmony_ci#define LTQ_SPI_FSTAT_TXFFL_S 8 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci#define LTQ_SPI_GPOCON_ISCSBN_S 8 13662306a36Sopenharmony_ci#define LTQ_SPI_GPOCON_INVOUTN_S 0 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci#define LTQ_SPI_FGPO_SETOUTN_S 8 13962306a36Sopenharmony_ci#define LTQ_SPI_FGPO_CLROUTN_S 0 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#define LTQ_SPI_RXREQ_RXCNT_M 0xFFFF /* Receive count value */ 14262306a36Sopenharmony_ci#define LTQ_SPI_RXCNT_TODO_M 0xFFFF /* Recevie to-do value */ 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_TFI BIT(4) /* TX finished interrupt */ 14562306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_F BIT(3) /* Frame end interrupt request */ 14662306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_E BIT(2) /* Error end interrupt request */ 14762306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_T_XWAY BIT(1) /* Transmit end interrupt request */ 14862306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_R_XWAY BIT(0) /* Receive end interrupt request */ 14962306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_R_XRX BIT(1) /* Transmit end interrupt request */ 15062306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_T_XRX BIT(0) /* Receive end interrupt request */ 15162306a36Sopenharmony_ci#define LTQ_SPI_IRNEN_ALL 0x1F 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistruct lantiq_ssc_spi; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistruct lantiq_ssc_hwcfg { 15662306a36Sopenharmony_ci int (*cfg_irq)(struct platform_device *pdev, struct lantiq_ssc_spi *spi); 15762306a36Sopenharmony_ci unsigned int irnen_r; 15862306a36Sopenharmony_ci unsigned int irnen_t; 15962306a36Sopenharmony_ci unsigned int irncr; 16062306a36Sopenharmony_ci unsigned int irnicr; 16162306a36Sopenharmony_ci bool irq_ack; 16262306a36Sopenharmony_ci u32 fifo_size_mask; 16362306a36Sopenharmony_ci}; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_cistruct lantiq_ssc_spi { 16662306a36Sopenharmony_ci struct spi_controller *host; 16762306a36Sopenharmony_ci struct device *dev; 16862306a36Sopenharmony_ci void __iomem *regbase; 16962306a36Sopenharmony_ci struct clk *spi_clk; 17062306a36Sopenharmony_ci struct clk *fpi_clk; 17162306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci spinlock_t lock; 17462306a36Sopenharmony_ci struct workqueue_struct *wq; 17562306a36Sopenharmony_ci struct work_struct work; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci const u8 *tx; 17862306a36Sopenharmony_ci u8 *rx; 17962306a36Sopenharmony_ci unsigned int tx_todo; 18062306a36Sopenharmony_ci unsigned int rx_todo; 18162306a36Sopenharmony_ci unsigned int bits_per_word; 18262306a36Sopenharmony_ci unsigned int speed_hz; 18362306a36Sopenharmony_ci unsigned int tx_fifo_size; 18462306a36Sopenharmony_ci unsigned int rx_fifo_size; 18562306a36Sopenharmony_ci unsigned int base_cs; 18662306a36Sopenharmony_ci unsigned int fdx_tx_level; 18762306a36Sopenharmony_ci}; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic u32 lantiq_ssc_readl(const struct lantiq_ssc_spi *spi, u32 reg) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci return __raw_readl(spi->regbase + reg); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void lantiq_ssc_writel(const struct lantiq_ssc_spi *spi, u32 val, 19562306a36Sopenharmony_ci u32 reg) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci __raw_writel(val, spi->regbase + reg); 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic void lantiq_ssc_maskl(const struct lantiq_ssc_spi *spi, u32 clr, 20162306a36Sopenharmony_ci u32 set, u32 reg) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci u32 val = __raw_readl(spi->regbase + reg); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci val &= ~clr; 20662306a36Sopenharmony_ci val |= set; 20762306a36Sopenharmony_ci __raw_writel(val, spi->regbase + reg); 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic unsigned int tx_fifo_level(const struct lantiq_ssc_spi *spi) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; 21362306a36Sopenharmony_ci u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return (fstat >> LTQ_SPI_FSTAT_TXFFL_S) & hwcfg->fifo_size_mask; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic unsigned int rx_fifo_level(const struct lantiq_ssc_spi *spi) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; 22162306a36Sopenharmony_ci u32 fstat = lantiq_ssc_readl(spi, LTQ_SPI_FSTAT); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return (fstat >> LTQ_SPI_FSTAT_RXFFL_S) & hwcfg->fifo_size_mask; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic unsigned int tx_fifo_free(const struct lantiq_ssc_spi *spi) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci return spi->tx_fifo_size - tx_fifo_level(spi); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic void rx_fifo_reset(const struct lantiq_ssc_spi *spi) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci u32 val = spi->rx_fifo_size << LTQ_SPI_RXFCON_RXFITL_S; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci val |= LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU; 23662306a36Sopenharmony_ci lantiq_ssc_writel(spi, val, LTQ_SPI_RXFCON); 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic void tx_fifo_reset(const struct lantiq_ssc_spi *spi) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci u32 val = 1 << LTQ_SPI_TXFCON_TXFITL_S; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci val |= LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU; 24462306a36Sopenharmony_ci lantiq_ssc_writel(spi, val, LTQ_SPI_TXFCON); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic void rx_fifo_flush(const struct lantiq_ssc_spi *spi) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci lantiq_ssc_maskl(spi, 0, LTQ_SPI_RXFCON_RXFLU, LTQ_SPI_RXFCON); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic void tx_fifo_flush(const struct lantiq_ssc_spi *spi) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci lantiq_ssc_maskl(spi, 0, LTQ_SPI_TXFCON_TXFLU, LTQ_SPI_TXFCON); 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_cistatic void hw_enter_config_mode(const struct lantiq_ssc_spi *spi) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_CLREN, LTQ_SPI_WHBSTATE); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void hw_enter_active_mode(const struct lantiq_ssc_spi *spi) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETEN, LTQ_SPI_WHBSTATE); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic void hw_setup_speed_hz(const struct lantiq_ssc_spi *spi, 26862306a36Sopenharmony_ci unsigned int max_speed_hz) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci u32 spi_clk, brt; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * SPI module clock is derived from FPI bus clock dependent on 27462306a36Sopenharmony_ci * divider value in CLC.RMS which is always set to 1. 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * f_SPI 27762306a36Sopenharmony_ci * baudrate = -------------- 27862306a36Sopenharmony_ci * 2 * (BR + 1) 27962306a36Sopenharmony_ci */ 28062306a36Sopenharmony_ci spi_clk = clk_get_rate(spi->fpi_clk) / 2; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci if (max_speed_hz > spi_clk) 28362306a36Sopenharmony_ci brt = 0; 28462306a36Sopenharmony_ci else 28562306a36Sopenharmony_ci brt = spi_clk / max_speed_hz - 1; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (brt > 0xFFFF) 28862306a36Sopenharmony_ci brt = 0xFFFF; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci dev_dbg(spi->dev, "spi_clk %u, max_speed_hz %u, brt %u\n", 29162306a36Sopenharmony_ci spi_clk, max_speed_hz, brt); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci lantiq_ssc_writel(spi, brt, LTQ_SPI_BRT); 29462306a36Sopenharmony_ci} 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_cistatic void hw_setup_bits_per_word(const struct lantiq_ssc_spi *spi, 29762306a36Sopenharmony_ci unsigned int bits_per_word) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci u32 bm; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* CON.BM value = bits_per_word - 1 */ 30262306a36Sopenharmony_ci bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_S; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci lantiq_ssc_maskl(spi, LTQ_SPI_CON_BM_M, bm, LTQ_SPI_CON); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void hw_setup_clock_mode(const struct lantiq_ssc_spi *spi, 30862306a36Sopenharmony_ci unsigned int mode) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci u32 con_set = 0, con_clr = 0; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * SPI mode mapping in CON register: 31462306a36Sopenharmony_ci * Mode CPOL CPHA CON.PO CON.PH 31562306a36Sopenharmony_ci * 0 0 0 0 1 31662306a36Sopenharmony_ci * 1 0 1 0 0 31762306a36Sopenharmony_ci * 2 1 0 1 1 31862306a36Sopenharmony_ci * 3 1 1 1 0 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci if (mode & SPI_CPHA) 32162306a36Sopenharmony_ci con_clr |= LTQ_SPI_CON_PH; 32262306a36Sopenharmony_ci else 32362306a36Sopenharmony_ci con_set |= LTQ_SPI_CON_PH; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci if (mode & SPI_CPOL) 32662306a36Sopenharmony_ci con_set |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE; 32762306a36Sopenharmony_ci else 32862306a36Sopenharmony_ci con_clr |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* Set heading control */ 33162306a36Sopenharmony_ci if (mode & SPI_LSB_FIRST) 33262306a36Sopenharmony_ci con_clr |= LTQ_SPI_CON_HB; 33362306a36Sopenharmony_ci else 33462306a36Sopenharmony_ci con_set |= LTQ_SPI_CON_HB; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* Set loopback mode */ 33762306a36Sopenharmony_ci if (mode & SPI_LOOP) 33862306a36Sopenharmony_ci con_set |= LTQ_SPI_CON_LB; 33962306a36Sopenharmony_ci else 34062306a36Sopenharmony_ci con_clr |= LTQ_SPI_CON_LB; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci lantiq_ssc_maskl(spi, con_clr, con_set, LTQ_SPI_CON); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic void lantiq_ssc_hw_init(const struct lantiq_ssc_spi *spi) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * Set clock divider for run mode to 1 to 35162306a36Sopenharmony_ci * run at same frequency as FPI bus 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci lantiq_ssc_writel(spi, 1 << LTQ_SPI_CLC_RMC_S, LTQ_SPI_CLC); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* Put controller into config mode */ 35662306a36Sopenharmony_ci hw_enter_config_mode(spi); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* Clear error flags */ 35962306a36Sopenharmony_ci lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Enable error checking, disable TX/RX */ 36262306a36Sopenharmony_ci lantiq_ssc_writel(spi, LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN | 36362306a36Sopenharmony_ci LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | LTQ_SPI_CON_TXOFF | 36462306a36Sopenharmony_ci LTQ_SPI_CON_RXOFF, LTQ_SPI_CON); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* Setup default SPI mode */ 36762306a36Sopenharmony_ci hw_setup_bits_per_word(spi, spi->bits_per_word); 36862306a36Sopenharmony_ci hw_setup_clock_mode(spi, SPI_MODE_0); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci /* Enable host mode and clear error flags */ 37162306a36Sopenharmony_ci lantiq_ssc_writel(spi, LTQ_SPI_WHBSTATE_SETMS | 37262306a36Sopenharmony_ci LTQ_SPI_WHBSTATE_CLR_ERRORS, 37362306a36Sopenharmony_ci LTQ_SPI_WHBSTATE); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci /* Reset GPIO/CS registers */ 37662306a36Sopenharmony_ci lantiq_ssc_writel(spi, 0, LTQ_SPI_GPOCON); 37762306a36Sopenharmony_ci lantiq_ssc_writel(spi, 0xFF00, LTQ_SPI_FPGO); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci /* Enable and flush FIFOs */ 38062306a36Sopenharmony_ci rx_fifo_reset(spi); 38162306a36Sopenharmony_ci tx_fifo_reset(spi); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Enable interrupts */ 38462306a36Sopenharmony_ci lantiq_ssc_writel(spi, hwcfg->irnen_t | hwcfg->irnen_r | 38562306a36Sopenharmony_ci LTQ_SPI_IRNEN_E, LTQ_SPI_IRNEN); 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int lantiq_ssc_setup(struct spi_device *spidev) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct spi_controller *host = spidev->controller; 39162306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host); 39262306a36Sopenharmony_ci unsigned int cs = spi_get_chipselect(spidev, 0); 39362306a36Sopenharmony_ci u32 gpocon; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* GPIOs are used for CS */ 39662306a36Sopenharmony_ci if (spi_get_csgpiod(spidev, 0)) 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci dev_dbg(spi->dev, "using internal chipselect %u\n", cs); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (cs < spi->base_cs) { 40262306a36Sopenharmony_ci dev_err(spi->dev, 40362306a36Sopenharmony_ci "chipselect %i too small (min %i)\n", cs, spi->base_cs); 40462306a36Sopenharmony_ci return -EINVAL; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* set GPO pin to CS mode */ 40862306a36Sopenharmony_ci gpocon = 1 << ((cs - spi->base_cs) + LTQ_SPI_GPOCON_ISCSBN_S); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* invert GPO pin */ 41162306a36Sopenharmony_ci if (spidev->mode & SPI_CS_HIGH) 41262306a36Sopenharmony_ci gpocon |= 1 << (cs - spi->base_cs); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci lantiq_ssc_maskl(spi, 0, gpocon, LTQ_SPI_GPOCON); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic int lantiq_ssc_prepare_message(struct spi_controller *host, 42062306a36Sopenharmony_ci struct spi_message *message) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci hw_enter_config_mode(spi); 42562306a36Sopenharmony_ci hw_setup_clock_mode(spi, message->spi->mode); 42662306a36Sopenharmony_ci hw_enter_active_mode(spi); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return 0; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void hw_setup_transfer(struct lantiq_ssc_spi *spi, 43262306a36Sopenharmony_ci struct spi_device *spidev, struct spi_transfer *t) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci unsigned int speed_hz = t->speed_hz; 43562306a36Sopenharmony_ci unsigned int bits_per_word = t->bits_per_word; 43662306a36Sopenharmony_ci u32 con; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (bits_per_word != spi->bits_per_word || 43962306a36Sopenharmony_ci speed_hz != spi->speed_hz) { 44062306a36Sopenharmony_ci hw_enter_config_mode(spi); 44162306a36Sopenharmony_ci hw_setup_speed_hz(spi, speed_hz); 44262306a36Sopenharmony_ci hw_setup_bits_per_word(spi, bits_per_word); 44362306a36Sopenharmony_ci hw_enter_active_mode(spi); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci spi->speed_hz = speed_hz; 44662306a36Sopenharmony_ci spi->bits_per_word = bits_per_word; 44762306a36Sopenharmony_ci } 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* Configure transmitter and receiver */ 45062306a36Sopenharmony_ci con = lantiq_ssc_readl(spi, LTQ_SPI_CON); 45162306a36Sopenharmony_ci if (t->tx_buf) 45262306a36Sopenharmony_ci con &= ~LTQ_SPI_CON_TXOFF; 45362306a36Sopenharmony_ci else 45462306a36Sopenharmony_ci con |= LTQ_SPI_CON_TXOFF; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (t->rx_buf) 45762306a36Sopenharmony_ci con &= ~LTQ_SPI_CON_RXOFF; 45862306a36Sopenharmony_ci else 45962306a36Sopenharmony_ci con |= LTQ_SPI_CON_RXOFF; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci lantiq_ssc_writel(spi, con, LTQ_SPI_CON); 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int lantiq_ssc_unprepare_message(struct spi_controller *host, 46562306a36Sopenharmony_ci struct spi_message *message) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci flush_workqueue(spi->wq); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci /* Disable transmitter and receiver while idle */ 47262306a36Sopenharmony_ci lantiq_ssc_maskl(spi, 0, LTQ_SPI_CON_TXOFF | LTQ_SPI_CON_RXOFF, 47362306a36Sopenharmony_ci LTQ_SPI_CON); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic void tx_fifo_write(struct lantiq_ssc_spi *spi) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci const u8 *tx8; 48162306a36Sopenharmony_ci const u16 *tx16; 48262306a36Sopenharmony_ci const u32 *tx32; 48362306a36Sopenharmony_ci u32 data; 48462306a36Sopenharmony_ci unsigned int tx_free = tx_fifo_free(spi); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci spi->fdx_tx_level = 0; 48762306a36Sopenharmony_ci while (spi->tx_todo && tx_free) { 48862306a36Sopenharmony_ci switch (spi->bits_per_word) { 48962306a36Sopenharmony_ci case 2 ... 8: 49062306a36Sopenharmony_ci tx8 = spi->tx; 49162306a36Sopenharmony_ci data = *tx8; 49262306a36Sopenharmony_ci spi->tx_todo--; 49362306a36Sopenharmony_ci spi->tx++; 49462306a36Sopenharmony_ci break; 49562306a36Sopenharmony_ci case 16: 49662306a36Sopenharmony_ci tx16 = (u16 *) spi->tx; 49762306a36Sopenharmony_ci data = *tx16; 49862306a36Sopenharmony_ci spi->tx_todo -= 2; 49962306a36Sopenharmony_ci spi->tx += 2; 50062306a36Sopenharmony_ci break; 50162306a36Sopenharmony_ci case 32: 50262306a36Sopenharmony_ci tx32 = (u32 *) spi->tx; 50362306a36Sopenharmony_ci data = *tx32; 50462306a36Sopenharmony_ci spi->tx_todo -= 4; 50562306a36Sopenharmony_ci spi->tx += 4; 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci default: 50862306a36Sopenharmony_ci WARN_ON(1); 50962306a36Sopenharmony_ci data = 0; 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci lantiq_ssc_writel(spi, data, LTQ_SPI_TB); 51462306a36Sopenharmony_ci tx_free--; 51562306a36Sopenharmony_ci spi->fdx_tx_level++; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic void rx_fifo_read_full_duplex(struct lantiq_ssc_spi *spi) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci u8 *rx8; 52262306a36Sopenharmony_ci u16 *rx16; 52362306a36Sopenharmony_ci u32 *rx32; 52462306a36Sopenharmony_ci u32 data; 52562306a36Sopenharmony_ci unsigned int rx_fill = rx_fifo_level(spi); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* 52862306a36Sopenharmony_ci * Wait until all expected data to be shifted in. 52962306a36Sopenharmony_ci * Otherwise, rx overrun may occur. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci while (rx_fill != spi->fdx_tx_level) 53262306a36Sopenharmony_ci rx_fill = rx_fifo_level(spi); 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci while (rx_fill) { 53562306a36Sopenharmony_ci data = lantiq_ssc_readl(spi, LTQ_SPI_RB); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci switch (spi->bits_per_word) { 53862306a36Sopenharmony_ci case 2 ... 8: 53962306a36Sopenharmony_ci rx8 = spi->rx; 54062306a36Sopenharmony_ci *rx8 = data; 54162306a36Sopenharmony_ci spi->rx_todo--; 54262306a36Sopenharmony_ci spi->rx++; 54362306a36Sopenharmony_ci break; 54462306a36Sopenharmony_ci case 16: 54562306a36Sopenharmony_ci rx16 = (u16 *) spi->rx; 54662306a36Sopenharmony_ci *rx16 = data; 54762306a36Sopenharmony_ci spi->rx_todo -= 2; 54862306a36Sopenharmony_ci spi->rx += 2; 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci case 32: 55162306a36Sopenharmony_ci rx32 = (u32 *) spi->rx; 55262306a36Sopenharmony_ci *rx32 = data; 55362306a36Sopenharmony_ci spi->rx_todo -= 4; 55462306a36Sopenharmony_ci spi->rx += 4; 55562306a36Sopenharmony_ci break; 55662306a36Sopenharmony_ci default: 55762306a36Sopenharmony_ci WARN_ON(1); 55862306a36Sopenharmony_ci break; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci rx_fill--; 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cistatic void rx_fifo_read_half_duplex(struct lantiq_ssc_spi *spi) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci u32 data, *rx32; 56862306a36Sopenharmony_ci u8 *rx8; 56962306a36Sopenharmony_ci unsigned int rxbv, shift; 57062306a36Sopenharmony_ci unsigned int rx_fill = rx_fifo_level(spi); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* 57362306a36Sopenharmony_ci * In RX-only mode the bits per word value is ignored by HW. A value 57462306a36Sopenharmony_ci * of 32 is used instead. Thus all 4 bytes per FIFO must be read. 57562306a36Sopenharmony_ci * If remaining RX bytes are less than 4, the FIFO must be read 57662306a36Sopenharmony_ci * differently. The amount of received and valid bytes is indicated 57762306a36Sopenharmony_ci * by STAT.RXBV register value. 57862306a36Sopenharmony_ci */ 57962306a36Sopenharmony_ci while (rx_fill) { 58062306a36Sopenharmony_ci if (spi->rx_todo < 4) { 58162306a36Sopenharmony_ci rxbv = (lantiq_ssc_readl(spi, LTQ_SPI_STAT) & 58262306a36Sopenharmony_ci LTQ_SPI_STAT_RXBV_M) >> LTQ_SPI_STAT_RXBV_S; 58362306a36Sopenharmony_ci data = lantiq_ssc_readl(spi, LTQ_SPI_RB); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci shift = (rxbv - 1) * 8; 58662306a36Sopenharmony_ci rx8 = spi->rx; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci while (rxbv) { 58962306a36Sopenharmony_ci *rx8++ = (data >> shift) & 0xFF; 59062306a36Sopenharmony_ci rxbv--; 59162306a36Sopenharmony_ci shift -= 8; 59262306a36Sopenharmony_ci spi->rx_todo--; 59362306a36Sopenharmony_ci spi->rx++; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci } else { 59662306a36Sopenharmony_ci data = lantiq_ssc_readl(spi, LTQ_SPI_RB); 59762306a36Sopenharmony_ci rx32 = (u32 *) spi->rx; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci *rx32++ = data; 60062306a36Sopenharmony_ci spi->rx_todo -= 4; 60162306a36Sopenharmony_ci spi->rx += 4; 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci rx_fill--; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic void rx_request(struct lantiq_ssc_spi *spi) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci unsigned int rxreq, rxreq_max; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* 61262306a36Sopenharmony_ci * To avoid receive overflows at high clocks it is better to request 61362306a36Sopenharmony_ci * only the amount of bytes that fits into all FIFOs. This value 61462306a36Sopenharmony_ci * depends on the FIFO size implemented in hardware. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci rxreq = spi->rx_todo; 61762306a36Sopenharmony_ci rxreq_max = spi->rx_fifo_size * 4; 61862306a36Sopenharmony_ci if (rxreq > rxreq_max) 61962306a36Sopenharmony_ci rxreq = rxreq_max; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci lantiq_ssc_writel(spi, rxreq, LTQ_SPI_RXREQ); 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_cistatic irqreturn_t lantiq_ssc_xmit_interrupt(int irq, void *data) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = data; 62762306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; 62862306a36Sopenharmony_ci u32 val = lantiq_ssc_readl(spi, hwcfg->irncr); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci spin_lock(&spi->lock); 63162306a36Sopenharmony_ci if (hwcfg->irq_ack) 63262306a36Sopenharmony_ci lantiq_ssc_writel(spi, val, hwcfg->irncr); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (spi->tx) { 63562306a36Sopenharmony_ci if (spi->rx && spi->rx_todo) 63662306a36Sopenharmony_ci rx_fifo_read_full_duplex(spi); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (spi->tx_todo) 63962306a36Sopenharmony_ci tx_fifo_write(spi); 64062306a36Sopenharmony_ci else if (!tx_fifo_level(spi)) 64162306a36Sopenharmony_ci goto completed; 64262306a36Sopenharmony_ci } else if (spi->rx) { 64362306a36Sopenharmony_ci if (spi->rx_todo) { 64462306a36Sopenharmony_ci rx_fifo_read_half_duplex(spi); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci if (spi->rx_todo) 64762306a36Sopenharmony_ci rx_request(spi); 64862306a36Sopenharmony_ci else 64962306a36Sopenharmony_ci goto completed; 65062306a36Sopenharmony_ci } else { 65162306a36Sopenharmony_ci goto completed; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci spin_unlock(&spi->lock); 65662306a36Sopenharmony_ci return IRQ_HANDLED; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cicompleted: 65962306a36Sopenharmony_ci queue_work(spi->wq, &spi->work); 66062306a36Sopenharmony_ci spin_unlock(&spi->lock); 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci return IRQ_HANDLED; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic irqreturn_t lantiq_ssc_err_interrupt(int irq, void *data) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = data; 66862306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; 66962306a36Sopenharmony_ci u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT); 67062306a36Sopenharmony_ci u32 val = lantiq_ssc_readl(spi, hwcfg->irncr); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (!(stat & LTQ_SPI_STAT_ERRORS)) 67362306a36Sopenharmony_ci return IRQ_NONE; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci spin_lock(&spi->lock); 67662306a36Sopenharmony_ci if (hwcfg->irq_ack) 67762306a36Sopenharmony_ci lantiq_ssc_writel(spi, val, hwcfg->irncr); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (stat & LTQ_SPI_STAT_RUE) 68062306a36Sopenharmony_ci dev_err(spi->dev, "receive underflow error\n"); 68162306a36Sopenharmony_ci if (stat & LTQ_SPI_STAT_TUE) 68262306a36Sopenharmony_ci dev_err(spi->dev, "transmit underflow error\n"); 68362306a36Sopenharmony_ci if (stat & LTQ_SPI_STAT_AE) 68462306a36Sopenharmony_ci dev_err(spi->dev, "abort error\n"); 68562306a36Sopenharmony_ci if (stat & LTQ_SPI_STAT_RE) 68662306a36Sopenharmony_ci dev_err(spi->dev, "receive overflow error\n"); 68762306a36Sopenharmony_ci if (stat & LTQ_SPI_STAT_TE) 68862306a36Sopenharmony_ci dev_err(spi->dev, "transmit overflow error\n"); 68962306a36Sopenharmony_ci if (stat & LTQ_SPI_STAT_ME) 69062306a36Sopenharmony_ci dev_err(spi->dev, "mode error\n"); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* Clear error flags */ 69362306a36Sopenharmony_ci lantiq_ssc_maskl(spi, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS, LTQ_SPI_WHBSTATE); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* set bad status so it can be retried */ 69662306a36Sopenharmony_ci if (spi->host->cur_msg) 69762306a36Sopenharmony_ci spi->host->cur_msg->status = -EIO; 69862306a36Sopenharmony_ci queue_work(spi->wq, &spi->work); 69962306a36Sopenharmony_ci spin_unlock(&spi->lock); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return IRQ_HANDLED; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic irqreturn_t intel_lgm_ssc_isr(int irq, void *data) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = data; 70762306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg = spi->hwcfg; 70862306a36Sopenharmony_ci u32 val = lantiq_ssc_readl(spi, hwcfg->irncr); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (!(val & LTQ_SPI_IRNEN_ALL)) 71162306a36Sopenharmony_ci return IRQ_NONE; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (val & LTQ_SPI_IRNEN_E) 71462306a36Sopenharmony_ci return lantiq_ssc_err_interrupt(irq, data); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if ((val & hwcfg->irnen_t) || (val & hwcfg->irnen_r)) 71762306a36Sopenharmony_ci return lantiq_ssc_xmit_interrupt(irq, data); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci return IRQ_HANDLED; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_cistatic int transfer_start(struct lantiq_ssc_spi *spi, struct spi_device *spidev, 72362306a36Sopenharmony_ci struct spi_transfer *t) 72462306a36Sopenharmony_ci{ 72562306a36Sopenharmony_ci unsigned long flags; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci spin_lock_irqsave(&spi->lock, flags); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci spi->tx = t->tx_buf; 73062306a36Sopenharmony_ci spi->rx = t->rx_buf; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (t->tx_buf) { 73362306a36Sopenharmony_ci spi->tx_todo = t->len; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci /* initially fill TX FIFO */ 73662306a36Sopenharmony_ci tx_fifo_write(spi); 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci if (spi->rx) { 74062306a36Sopenharmony_ci spi->rx_todo = t->len; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* start shift clock in RX-only mode */ 74362306a36Sopenharmony_ci if (!spi->tx) 74462306a36Sopenharmony_ci rx_request(spi); 74562306a36Sopenharmony_ci } 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci spin_unlock_irqrestore(&spi->lock, flags); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return t->len; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci/* 75362306a36Sopenharmony_ci * The driver only gets an interrupt when the FIFO is empty, but there 75462306a36Sopenharmony_ci * is an additional shift register from which the data is written to 75562306a36Sopenharmony_ci * the wire. We get the last interrupt when the controller starts to 75662306a36Sopenharmony_ci * write the last word to the wire, not when it is finished. Do busy 75762306a36Sopenharmony_ci * waiting till it finishes. 75862306a36Sopenharmony_ci */ 75962306a36Sopenharmony_cistatic void lantiq_ssc_bussy_work(struct work_struct *work) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct lantiq_ssc_spi *spi; 76262306a36Sopenharmony_ci unsigned long long timeout = 8LL * 1000LL; 76362306a36Sopenharmony_ci unsigned long end; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci spi = container_of(work, typeof(*spi), work); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci do_div(timeout, spi->speed_hz); 76862306a36Sopenharmony_ci timeout += timeout + 100; /* some tolerance */ 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci end = jiffies + msecs_to_jiffies(timeout); 77162306a36Sopenharmony_ci do { 77262306a36Sopenharmony_ci u32 stat = lantiq_ssc_readl(spi, LTQ_SPI_STAT); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (!(stat & LTQ_SPI_STAT_BSY)) { 77562306a36Sopenharmony_ci spi_finalize_current_transfer(spi->host); 77662306a36Sopenharmony_ci return; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci cond_resched(); 78062306a36Sopenharmony_ci } while (!time_after_eq(jiffies, end)); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (spi->host->cur_msg) 78362306a36Sopenharmony_ci spi->host->cur_msg->status = -EIO; 78462306a36Sopenharmony_ci spi_finalize_current_transfer(spi->host); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void lantiq_ssc_handle_err(struct spi_controller *host, 78862306a36Sopenharmony_ci struct spi_message *message) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* flush FIFOs on timeout */ 79362306a36Sopenharmony_ci rx_fifo_flush(spi); 79462306a36Sopenharmony_ci tx_fifo_flush(spi); 79562306a36Sopenharmony_ci} 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_cistatic void lantiq_ssc_set_cs(struct spi_device *spidev, bool enable) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = spi_controller_get_devdata(spidev->controller); 80062306a36Sopenharmony_ci unsigned int cs = spi_get_chipselect(spidev, 0); 80162306a36Sopenharmony_ci u32 fgpo; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci if (!!(spidev->mode & SPI_CS_HIGH) == enable) 80462306a36Sopenharmony_ci fgpo = (1 << (cs - spi->base_cs)); 80562306a36Sopenharmony_ci else 80662306a36Sopenharmony_ci fgpo = (1 << (cs - spi->base_cs + LTQ_SPI_FGPO_SETOUTN_S)); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci lantiq_ssc_writel(spi, fgpo, LTQ_SPI_FPGO); 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic int lantiq_ssc_transfer_one(struct spi_controller *host, 81262306a36Sopenharmony_ci struct spi_device *spidev, 81362306a36Sopenharmony_ci struct spi_transfer *t) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = spi_controller_get_devdata(host); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci hw_setup_transfer(spi, spidev, t); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return transfer_start(spi, spidev, t); 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic int intel_lgm_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci int irq; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 82762306a36Sopenharmony_ci if (irq < 0) 82862306a36Sopenharmony_ci return irq; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci return devm_request_irq(&pdev->dev, irq, intel_lgm_ssc_isr, 0, "spi", spi); 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic int lantiq_cfg_irq(struct platform_device *pdev, struct lantiq_ssc_spi *spi) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci int irq, err; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, LTQ_SPI_RX_IRQ_NAME); 83862306a36Sopenharmony_ci if (irq < 0) 83962306a36Sopenharmony_ci return irq; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt, 84262306a36Sopenharmony_ci 0, LTQ_SPI_RX_IRQ_NAME, spi); 84362306a36Sopenharmony_ci if (err) 84462306a36Sopenharmony_ci return err; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, LTQ_SPI_TX_IRQ_NAME); 84762306a36Sopenharmony_ci if (irq < 0) 84862306a36Sopenharmony_ci return irq; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_xmit_interrupt, 85162306a36Sopenharmony_ci 0, LTQ_SPI_TX_IRQ_NAME, spi); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (err) 85462306a36Sopenharmony_ci return err; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, LTQ_SPI_ERR_IRQ_NAME); 85762306a36Sopenharmony_ci if (irq < 0) 85862306a36Sopenharmony_ci return irq; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, lantiq_ssc_err_interrupt, 86162306a36Sopenharmony_ci 0, LTQ_SPI_ERR_IRQ_NAME, spi); 86262306a36Sopenharmony_ci return err; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic const struct lantiq_ssc_hwcfg lantiq_ssc_xway = { 86662306a36Sopenharmony_ci .cfg_irq = lantiq_cfg_irq, 86762306a36Sopenharmony_ci .irnen_r = LTQ_SPI_IRNEN_R_XWAY, 86862306a36Sopenharmony_ci .irnen_t = LTQ_SPI_IRNEN_T_XWAY, 86962306a36Sopenharmony_ci .irnicr = 0xF8, 87062306a36Sopenharmony_ci .irncr = 0xFC, 87162306a36Sopenharmony_ci .fifo_size_mask = GENMASK(5, 0), 87262306a36Sopenharmony_ci .irq_ack = false, 87362306a36Sopenharmony_ci}; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_cistatic const struct lantiq_ssc_hwcfg lantiq_ssc_xrx = { 87662306a36Sopenharmony_ci .cfg_irq = lantiq_cfg_irq, 87762306a36Sopenharmony_ci .irnen_r = LTQ_SPI_IRNEN_R_XRX, 87862306a36Sopenharmony_ci .irnen_t = LTQ_SPI_IRNEN_T_XRX, 87962306a36Sopenharmony_ci .irnicr = 0xF8, 88062306a36Sopenharmony_ci .irncr = 0xFC, 88162306a36Sopenharmony_ci .fifo_size_mask = GENMASK(5, 0), 88262306a36Sopenharmony_ci .irq_ack = false, 88362306a36Sopenharmony_ci}; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic const struct lantiq_ssc_hwcfg intel_ssc_lgm = { 88662306a36Sopenharmony_ci .cfg_irq = intel_lgm_cfg_irq, 88762306a36Sopenharmony_ci .irnen_r = LTQ_SPI_IRNEN_R_XRX, 88862306a36Sopenharmony_ci .irnen_t = LTQ_SPI_IRNEN_T_XRX, 88962306a36Sopenharmony_ci .irnicr = 0xFC, 89062306a36Sopenharmony_ci .irncr = 0xF8, 89162306a36Sopenharmony_ci .fifo_size_mask = GENMASK(7, 0), 89262306a36Sopenharmony_ci .irq_ack = true, 89362306a36Sopenharmony_ci}; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_cistatic const struct of_device_id lantiq_ssc_match[] = { 89662306a36Sopenharmony_ci { .compatible = "lantiq,ase-spi", .data = &lantiq_ssc_xway, }, 89762306a36Sopenharmony_ci { .compatible = "lantiq,falcon-spi", .data = &lantiq_ssc_xrx, }, 89862306a36Sopenharmony_ci { .compatible = "lantiq,xrx100-spi", .data = &lantiq_ssc_xrx, }, 89962306a36Sopenharmony_ci { .compatible = "intel,lgm-spi", .data = &intel_ssc_lgm, }, 90062306a36Sopenharmony_ci {}, 90162306a36Sopenharmony_ci}; 90262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lantiq_ssc_match); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_cistatic int lantiq_ssc_probe(struct platform_device *pdev) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct device *dev = &pdev->dev; 90762306a36Sopenharmony_ci struct spi_controller *host; 90862306a36Sopenharmony_ci struct lantiq_ssc_spi *spi; 90962306a36Sopenharmony_ci const struct lantiq_ssc_hwcfg *hwcfg; 91062306a36Sopenharmony_ci u32 id, supports_dma, revision; 91162306a36Sopenharmony_ci unsigned int num_cs; 91262306a36Sopenharmony_ci int err; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci hwcfg = of_device_get_match_data(dev); 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci host = spi_alloc_host(dev, sizeof(struct lantiq_ssc_spi)); 91762306a36Sopenharmony_ci if (!host) 91862306a36Sopenharmony_ci return -ENOMEM; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci spi = spi_controller_get_devdata(host); 92162306a36Sopenharmony_ci spi->host = host; 92262306a36Sopenharmony_ci spi->dev = dev; 92362306a36Sopenharmony_ci spi->hwcfg = hwcfg; 92462306a36Sopenharmony_ci platform_set_drvdata(pdev, spi); 92562306a36Sopenharmony_ci spi->regbase = devm_platform_ioremap_resource(pdev, 0); 92662306a36Sopenharmony_ci if (IS_ERR(spi->regbase)) { 92762306a36Sopenharmony_ci err = PTR_ERR(spi->regbase); 92862306a36Sopenharmony_ci goto err_host_put; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci err = hwcfg->cfg_irq(pdev, spi); 93262306a36Sopenharmony_ci if (err) 93362306a36Sopenharmony_ci goto err_host_put; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci spi->spi_clk = devm_clk_get(dev, "gate"); 93662306a36Sopenharmony_ci if (IS_ERR(spi->spi_clk)) { 93762306a36Sopenharmony_ci err = PTR_ERR(spi->spi_clk); 93862306a36Sopenharmony_ci goto err_host_put; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci err = clk_prepare_enable(spi->spi_clk); 94162306a36Sopenharmony_ci if (err) 94262306a36Sopenharmony_ci goto err_host_put; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci /* 94562306a36Sopenharmony_ci * Use the old clk_get_fpi() function on Lantiq platform, till it 94662306a36Sopenharmony_ci * supports common clk. 94762306a36Sopenharmony_ci */ 94862306a36Sopenharmony_ci#if defined(CONFIG_LANTIQ) && !defined(CONFIG_COMMON_CLK) 94962306a36Sopenharmony_ci spi->fpi_clk = clk_get_fpi(); 95062306a36Sopenharmony_ci#else 95162306a36Sopenharmony_ci spi->fpi_clk = clk_get(dev, "freq"); 95262306a36Sopenharmony_ci#endif 95362306a36Sopenharmony_ci if (IS_ERR(spi->fpi_clk)) { 95462306a36Sopenharmony_ci err = PTR_ERR(spi->fpi_clk); 95562306a36Sopenharmony_ci goto err_clk_disable; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci num_cs = 8; 95962306a36Sopenharmony_ci of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci spi->base_cs = 1; 96262306a36Sopenharmony_ci of_property_read_u32(pdev->dev.of_node, "base-cs", &spi->base_cs); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci spin_lock_init(&spi->lock); 96562306a36Sopenharmony_ci spi->bits_per_word = 8; 96662306a36Sopenharmony_ci spi->speed_hz = 0; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci host->dev.of_node = pdev->dev.of_node; 96962306a36Sopenharmony_ci host->num_chipselect = num_cs; 97062306a36Sopenharmony_ci host->use_gpio_descriptors = true; 97162306a36Sopenharmony_ci host->setup = lantiq_ssc_setup; 97262306a36Sopenharmony_ci host->set_cs = lantiq_ssc_set_cs; 97362306a36Sopenharmony_ci host->handle_err = lantiq_ssc_handle_err; 97462306a36Sopenharmony_ci host->prepare_message = lantiq_ssc_prepare_message; 97562306a36Sopenharmony_ci host->unprepare_message = lantiq_ssc_unprepare_message; 97662306a36Sopenharmony_ci host->transfer_one = lantiq_ssc_transfer_one; 97762306a36Sopenharmony_ci host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH | 97862306a36Sopenharmony_ci SPI_LOOP; 97962306a36Sopenharmony_ci host->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 8) | 98062306a36Sopenharmony_ci SPI_BPW_MASK(16) | SPI_BPW_MASK(32); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci spi->wq = alloc_ordered_workqueue(dev_name(dev), WQ_MEM_RECLAIM); 98362306a36Sopenharmony_ci if (!spi->wq) { 98462306a36Sopenharmony_ci err = -ENOMEM; 98562306a36Sopenharmony_ci goto err_clk_put; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci INIT_WORK(&spi->work, lantiq_ssc_bussy_work); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci id = lantiq_ssc_readl(spi, LTQ_SPI_ID); 99062306a36Sopenharmony_ci spi->tx_fifo_size = (id >> LTQ_SPI_ID_TXFS_S) & hwcfg->fifo_size_mask; 99162306a36Sopenharmony_ci spi->rx_fifo_size = (id >> LTQ_SPI_ID_RXFS_S) & hwcfg->fifo_size_mask; 99262306a36Sopenharmony_ci supports_dma = (id & LTQ_SPI_ID_CFG_M) >> LTQ_SPI_ID_CFG_S; 99362306a36Sopenharmony_ci revision = id & LTQ_SPI_ID_REV_M; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci lantiq_ssc_hw_init(spi); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci dev_info(dev, 99862306a36Sopenharmony_ci "Lantiq SSC SPI controller (Rev %i, TXFS %u, RXFS %u, DMA %u)\n", 99962306a36Sopenharmony_ci revision, spi->tx_fifo_size, spi->rx_fifo_size, supports_dma); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci err = devm_spi_register_controller(dev, host); 100262306a36Sopenharmony_ci if (err) { 100362306a36Sopenharmony_ci dev_err(dev, "failed to register spi host\n"); 100462306a36Sopenharmony_ci goto err_wq_destroy; 100562306a36Sopenharmony_ci } 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci return 0; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cierr_wq_destroy: 101062306a36Sopenharmony_ci destroy_workqueue(spi->wq); 101162306a36Sopenharmony_cierr_clk_put: 101262306a36Sopenharmony_ci clk_put(spi->fpi_clk); 101362306a36Sopenharmony_cierr_clk_disable: 101462306a36Sopenharmony_ci clk_disable_unprepare(spi->spi_clk); 101562306a36Sopenharmony_cierr_host_put: 101662306a36Sopenharmony_ci spi_controller_put(host); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci return err; 101962306a36Sopenharmony_ci} 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic void lantiq_ssc_remove(struct platform_device *pdev) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci struct lantiq_ssc_spi *spi = platform_get_drvdata(pdev); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci lantiq_ssc_writel(spi, 0, LTQ_SPI_IRNEN); 102662306a36Sopenharmony_ci lantiq_ssc_writel(spi, 0, LTQ_SPI_CLC); 102762306a36Sopenharmony_ci rx_fifo_flush(spi); 102862306a36Sopenharmony_ci tx_fifo_flush(spi); 102962306a36Sopenharmony_ci hw_enter_config_mode(spi); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci destroy_workqueue(spi->wq); 103262306a36Sopenharmony_ci clk_disable_unprepare(spi->spi_clk); 103362306a36Sopenharmony_ci clk_put(spi->fpi_clk); 103462306a36Sopenharmony_ci} 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_cistatic struct platform_driver lantiq_ssc_driver = { 103762306a36Sopenharmony_ci .probe = lantiq_ssc_probe, 103862306a36Sopenharmony_ci .remove_new = lantiq_ssc_remove, 103962306a36Sopenharmony_ci .driver = { 104062306a36Sopenharmony_ci .name = "spi-lantiq-ssc", 104162306a36Sopenharmony_ci .of_match_table = lantiq_ssc_match, 104262306a36Sopenharmony_ci }, 104362306a36Sopenharmony_ci}; 104462306a36Sopenharmony_cimodule_platform_driver(lantiq_ssc_driver); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ciMODULE_DESCRIPTION("Lantiq SSC SPI controller driver"); 104762306a36Sopenharmony_ciMODULE_AUTHOR("Daniel Schwierzeck <daniel.schwierzeck@gmail.com>"); 104862306a36Sopenharmony_ciMODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>"); 104962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 105062306a36Sopenharmony_ciMODULE_ALIAS("platform:spi-lantiq-ssc"); 1051