18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for Atmel AT32 and AT91 SPI Controllers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Atmel Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 148c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 178c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/of.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/io.h> 228c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 238c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 248c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 258c2ecf20Sopenharmony_ci#include <trace/events/spi.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* SPI register offsets */ 288c2ecf20Sopenharmony_ci#define SPI_CR 0x0000 298c2ecf20Sopenharmony_ci#define SPI_MR 0x0004 308c2ecf20Sopenharmony_ci#define SPI_RDR 0x0008 318c2ecf20Sopenharmony_ci#define SPI_TDR 0x000c 328c2ecf20Sopenharmony_ci#define SPI_SR 0x0010 338c2ecf20Sopenharmony_ci#define SPI_IER 0x0014 348c2ecf20Sopenharmony_ci#define SPI_IDR 0x0018 358c2ecf20Sopenharmony_ci#define SPI_IMR 0x001c 368c2ecf20Sopenharmony_ci#define SPI_CSR0 0x0030 378c2ecf20Sopenharmony_ci#define SPI_CSR1 0x0034 388c2ecf20Sopenharmony_ci#define SPI_CSR2 0x0038 398c2ecf20Sopenharmony_ci#define SPI_CSR3 0x003c 408c2ecf20Sopenharmony_ci#define SPI_FMR 0x0040 418c2ecf20Sopenharmony_ci#define SPI_FLR 0x0044 428c2ecf20Sopenharmony_ci#define SPI_VERSION 0x00fc 438c2ecf20Sopenharmony_ci#define SPI_RPR 0x0100 448c2ecf20Sopenharmony_ci#define SPI_RCR 0x0104 458c2ecf20Sopenharmony_ci#define SPI_TPR 0x0108 468c2ecf20Sopenharmony_ci#define SPI_TCR 0x010c 478c2ecf20Sopenharmony_ci#define SPI_RNPR 0x0110 488c2ecf20Sopenharmony_ci#define SPI_RNCR 0x0114 498c2ecf20Sopenharmony_ci#define SPI_TNPR 0x0118 508c2ecf20Sopenharmony_ci#define SPI_TNCR 0x011c 518c2ecf20Sopenharmony_ci#define SPI_PTCR 0x0120 528c2ecf20Sopenharmony_ci#define SPI_PTSR 0x0124 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Bitfields in CR */ 558c2ecf20Sopenharmony_ci#define SPI_SPIEN_OFFSET 0 568c2ecf20Sopenharmony_ci#define SPI_SPIEN_SIZE 1 578c2ecf20Sopenharmony_ci#define SPI_SPIDIS_OFFSET 1 588c2ecf20Sopenharmony_ci#define SPI_SPIDIS_SIZE 1 598c2ecf20Sopenharmony_ci#define SPI_SWRST_OFFSET 7 608c2ecf20Sopenharmony_ci#define SPI_SWRST_SIZE 1 618c2ecf20Sopenharmony_ci#define SPI_LASTXFER_OFFSET 24 628c2ecf20Sopenharmony_ci#define SPI_LASTXFER_SIZE 1 638c2ecf20Sopenharmony_ci#define SPI_TXFCLR_OFFSET 16 648c2ecf20Sopenharmony_ci#define SPI_TXFCLR_SIZE 1 658c2ecf20Sopenharmony_ci#define SPI_RXFCLR_OFFSET 17 668c2ecf20Sopenharmony_ci#define SPI_RXFCLR_SIZE 1 678c2ecf20Sopenharmony_ci#define SPI_FIFOEN_OFFSET 30 688c2ecf20Sopenharmony_ci#define SPI_FIFOEN_SIZE 1 698c2ecf20Sopenharmony_ci#define SPI_FIFODIS_OFFSET 31 708c2ecf20Sopenharmony_ci#define SPI_FIFODIS_SIZE 1 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci/* Bitfields in MR */ 738c2ecf20Sopenharmony_ci#define SPI_MSTR_OFFSET 0 748c2ecf20Sopenharmony_ci#define SPI_MSTR_SIZE 1 758c2ecf20Sopenharmony_ci#define SPI_PS_OFFSET 1 768c2ecf20Sopenharmony_ci#define SPI_PS_SIZE 1 778c2ecf20Sopenharmony_ci#define SPI_PCSDEC_OFFSET 2 788c2ecf20Sopenharmony_ci#define SPI_PCSDEC_SIZE 1 798c2ecf20Sopenharmony_ci#define SPI_FDIV_OFFSET 3 808c2ecf20Sopenharmony_ci#define SPI_FDIV_SIZE 1 818c2ecf20Sopenharmony_ci#define SPI_MODFDIS_OFFSET 4 828c2ecf20Sopenharmony_ci#define SPI_MODFDIS_SIZE 1 838c2ecf20Sopenharmony_ci#define SPI_WDRBT_OFFSET 5 848c2ecf20Sopenharmony_ci#define SPI_WDRBT_SIZE 1 858c2ecf20Sopenharmony_ci#define SPI_LLB_OFFSET 7 868c2ecf20Sopenharmony_ci#define SPI_LLB_SIZE 1 878c2ecf20Sopenharmony_ci#define SPI_PCS_OFFSET 16 888c2ecf20Sopenharmony_ci#define SPI_PCS_SIZE 4 898c2ecf20Sopenharmony_ci#define SPI_DLYBCS_OFFSET 24 908c2ecf20Sopenharmony_ci#define SPI_DLYBCS_SIZE 8 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Bitfields in RDR */ 938c2ecf20Sopenharmony_ci#define SPI_RD_OFFSET 0 948c2ecf20Sopenharmony_ci#define SPI_RD_SIZE 16 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* Bitfields in TDR */ 978c2ecf20Sopenharmony_ci#define SPI_TD_OFFSET 0 988c2ecf20Sopenharmony_ci#define SPI_TD_SIZE 16 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* Bitfields in SR */ 1018c2ecf20Sopenharmony_ci#define SPI_RDRF_OFFSET 0 1028c2ecf20Sopenharmony_ci#define SPI_RDRF_SIZE 1 1038c2ecf20Sopenharmony_ci#define SPI_TDRE_OFFSET 1 1048c2ecf20Sopenharmony_ci#define SPI_TDRE_SIZE 1 1058c2ecf20Sopenharmony_ci#define SPI_MODF_OFFSET 2 1068c2ecf20Sopenharmony_ci#define SPI_MODF_SIZE 1 1078c2ecf20Sopenharmony_ci#define SPI_OVRES_OFFSET 3 1088c2ecf20Sopenharmony_ci#define SPI_OVRES_SIZE 1 1098c2ecf20Sopenharmony_ci#define SPI_ENDRX_OFFSET 4 1108c2ecf20Sopenharmony_ci#define SPI_ENDRX_SIZE 1 1118c2ecf20Sopenharmony_ci#define SPI_ENDTX_OFFSET 5 1128c2ecf20Sopenharmony_ci#define SPI_ENDTX_SIZE 1 1138c2ecf20Sopenharmony_ci#define SPI_RXBUFF_OFFSET 6 1148c2ecf20Sopenharmony_ci#define SPI_RXBUFF_SIZE 1 1158c2ecf20Sopenharmony_ci#define SPI_TXBUFE_OFFSET 7 1168c2ecf20Sopenharmony_ci#define SPI_TXBUFE_SIZE 1 1178c2ecf20Sopenharmony_ci#define SPI_NSSR_OFFSET 8 1188c2ecf20Sopenharmony_ci#define SPI_NSSR_SIZE 1 1198c2ecf20Sopenharmony_ci#define SPI_TXEMPTY_OFFSET 9 1208c2ecf20Sopenharmony_ci#define SPI_TXEMPTY_SIZE 1 1218c2ecf20Sopenharmony_ci#define SPI_SPIENS_OFFSET 16 1228c2ecf20Sopenharmony_ci#define SPI_SPIENS_SIZE 1 1238c2ecf20Sopenharmony_ci#define SPI_TXFEF_OFFSET 24 1248c2ecf20Sopenharmony_ci#define SPI_TXFEF_SIZE 1 1258c2ecf20Sopenharmony_ci#define SPI_TXFFF_OFFSET 25 1268c2ecf20Sopenharmony_ci#define SPI_TXFFF_SIZE 1 1278c2ecf20Sopenharmony_ci#define SPI_TXFTHF_OFFSET 26 1288c2ecf20Sopenharmony_ci#define SPI_TXFTHF_SIZE 1 1298c2ecf20Sopenharmony_ci#define SPI_RXFEF_OFFSET 27 1308c2ecf20Sopenharmony_ci#define SPI_RXFEF_SIZE 1 1318c2ecf20Sopenharmony_ci#define SPI_RXFFF_OFFSET 28 1328c2ecf20Sopenharmony_ci#define SPI_RXFFF_SIZE 1 1338c2ecf20Sopenharmony_ci#define SPI_RXFTHF_OFFSET 29 1348c2ecf20Sopenharmony_ci#define SPI_RXFTHF_SIZE 1 1358c2ecf20Sopenharmony_ci#define SPI_TXFPTEF_OFFSET 30 1368c2ecf20Sopenharmony_ci#define SPI_TXFPTEF_SIZE 1 1378c2ecf20Sopenharmony_ci#define SPI_RXFPTEF_OFFSET 31 1388c2ecf20Sopenharmony_ci#define SPI_RXFPTEF_SIZE 1 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci/* Bitfields in CSR0 */ 1418c2ecf20Sopenharmony_ci#define SPI_CPOL_OFFSET 0 1428c2ecf20Sopenharmony_ci#define SPI_CPOL_SIZE 1 1438c2ecf20Sopenharmony_ci#define SPI_NCPHA_OFFSET 1 1448c2ecf20Sopenharmony_ci#define SPI_NCPHA_SIZE 1 1458c2ecf20Sopenharmony_ci#define SPI_CSAAT_OFFSET 3 1468c2ecf20Sopenharmony_ci#define SPI_CSAAT_SIZE 1 1478c2ecf20Sopenharmony_ci#define SPI_BITS_OFFSET 4 1488c2ecf20Sopenharmony_ci#define SPI_BITS_SIZE 4 1498c2ecf20Sopenharmony_ci#define SPI_SCBR_OFFSET 8 1508c2ecf20Sopenharmony_ci#define SPI_SCBR_SIZE 8 1518c2ecf20Sopenharmony_ci#define SPI_DLYBS_OFFSET 16 1528c2ecf20Sopenharmony_ci#define SPI_DLYBS_SIZE 8 1538c2ecf20Sopenharmony_ci#define SPI_DLYBCT_OFFSET 24 1548c2ecf20Sopenharmony_ci#define SPI_DLYBCT_SIZE 8 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* Bitfields in RCR */ 1578c2ecf20Sopenharmony_ci#define SPI_RXCTR_OFFSET 0 1588c2ecf20Sopenharmony_ci#define SPI_RXCTR_SIZE 16 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* Bitfields in TCR */ 1618c2ecf20Sopenharmony_ci#define SPI_TXCTR_OFFSET 0 1628c2ecf20Sopenharmony_ci#define SPI_TXCTR_SIZE 16 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* Bitfields in RNCR */ 1658c2ecf20Sopenharmony_ci#define SPI_RXNCR_OFFSET 0 1668c2ecf20Sopenharmony_ci#define SPI_RXNCR_SIZE 16 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci/* Bitfields in TNCR */ 1698c2ecf20Sopenharmony_ci#define SPI_TXNCR_OFFSET 0 1708c2ecf20Sopenharmony_ci#define SPI_TXNCR_SIZE 16 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* Bitfields in PTCR */ 1738c2ecf20Sopenharmony_ci#define SPI_RXTEN_OFFSET 0 1748c2ecf20Sopenharmony_ci#define SPI_RXTEN_SIZE 1 1758c2ecf20Sopenharmony_ci#define SPI_RXTDIS_OFFSET 1 1768c2ecf20Sopenharmony_ci#define SPI_RXTDIS_SIZE 1 1778c2ecf20Sopenharmony_ci#define SPI_TXTEN_OFFSET 8 1788c2ecf20Sopenharmony_ci#define SPI_TXTEN_SIZE 1 1798c2ecf20Sopenharmony_ci#define SPI_TXTDIS_OFFSET 9 1808c2ecf20Sopenharmony_ci#define SPI_TXTDIS_SIZE 1 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Bitfields in FMR */ 1838c2ecf20Sopenharmony_ci#define SPI_TXRDYM_OFFSET 0 1848c2ecf20Sopenharmony_ci#define SPI_TXRDYM_SIZE 2 1858c2ecf20Sopenharmony_ci#define SPI_RXRDYM_OFFSET 4 1868c2ecf20Sopenharmony_ci#define SPI_RXRDYM_SIZE 2 1878c2ecf20Sopenharmony_ci#define SPI_TXFTHRES_OFFSET 16 1888c2ecf20Sopenharmony_ci#define SPI_TXFTHRES_SIZE 6 1898c2ecf20Sopenharmony_ci#define SPI_RXFTHRES_OFFSET 24 1908c2ecf20Sopenharmony_ci#define SPI_RXFTHRES_SIZE 6 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* Bitfields in FLR */ 1938c2ecf20Sopenharmony_ci#define SPI_TXFL_OFFSET 0 1948c2ecf20Sopenharmony_ci#define SPI_TXFL_SIZE 6 1958c2ecf20Sopenharmony_ci#define SPI_RXFL_OFFSET 16 1968c2ecf20Sopenharmony_ci#define SPI_RXFL_SIZE 6 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* Constants for BITS */ 1998c2ecf20Sopenharmony_ci#define SPI_BITS_8_BPT 0 2008c2ecf20Sopenharmony_ci#define SPI_BITS_9_BPT 1 2018c2ecf20Sopenharmony_ci#define SPI_BITS_10_BPT 2 2028c2ecf20Sopenharmony_ci#define SPI_BITS_11_BPT 3 2038c2ecf20Sopenharmony_ci#define SPI_BITS_12_BPT 4 2048c2ecf20Sopenharmony_ci#define SPI_BITS_13_BPT 5 2058c2ecf20Sopenharmony_ci#define SPI_BITS_14_BPT 6 2068c2ecf20Sopenharmony_ci#define SPI_BITS_15_BPT 7 2078c2ecf20Sopenharmony_ci#define SPI_BITS_16_BPT 8 2088c2ecf20Sopenharmony_ci#define SPI_ONE_DATA 0 2098c2ecf20Sopenharmony_ci#define SPI_TWO_DATA 1 2108c2ecf20Sopenharmony_ci#define SPI_FOUR_DATA 2 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/* Bit manipulation macros */ 2138c2ecf20Sopenharmony_ci#define SPI_BIT(name) \ 2148c2ecf20Sopenharmony_ci (1 << SPI_##name##_OFFSET) 2158c2ecf20Sopenharmony_ci#define SPI_BF(name, value) \ 2168c2ecf20Sopenharmony_ci (((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET) 2178c2ecf20Sopenharmony_ci#define SPI_BFEXT(name, value) \ 2188c2ecf20Sopenharmony_ci (((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1)) 2198c2ecf20Sopenharmony_ci#define SPI_BFINS(name, value, old) \ 2208c2ecf20Sopenharmony_ci (((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \ 2218c2ecf20Sopenharmony_ci | SPI_BF(name, value)) 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* Register access macros */ 2248c2ecf20Sopenharmony_ci#define spi_readl(port, reg) \ 2258c2ecf20Sopenharmony_ci readl_relaxed((port)->regs + SPI_##reg) 2268c2ecf20Sopenharmony_ci#define spi_writel(port, reg, value) \ 2278c2ecf20Sopenharmony_ci writel_relaxed((value), (port)->regs + SPI_##reg) 2288c2ecf20Sopenharmony_ci#define spi_writew(port, reg, value) \ 2298c2ecf20Sopenharmony_ci writew_relaxed((value), (port)->regs + SPI_##reg) 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* use PIO for small transfers, avoiding DMA setup/teardown overhead and 2328c2ecf20Sopenharmony_ci * cache operations; better heuristics consider wordsize and bitrate. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci#define DMA_MIN_BYTES 16 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000)) 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci#define AUTOSUSPEND_TIMEOUT 2000 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistruct atmel_spi_caps { 2418c2ecf20Sopenharmony_ci bool is_spi2; 2428c2ecf20Sopenharmony_ci bool has_wdrbt; 2438c2ecf20Sopenharmony_ci bool has_dma_support; 2448c2ecf20Sopenharmony_ci bool has_pdc_support; 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci/* 2488c2ecf20Sopenharmony_ci * The core SPI transfer engine just talks to a register bank to set up 2498c2ecf20Sopenharmony_ci * DMA transfers; transfer queue progress is driven by IRQs. The clock 2508c2ecf20Sopenharmony_ci * framework provides the base clock, subdivided for each spi_device. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_cistruct atmel_spi { 2538c2ecf20Sopenharmony_ci spinlock_t lock; 2548c2ecf20Sopenharmony_ci unsigned long flags; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci phys_addr_t phybase; 2578c2ecf20Sopenharmony_ci void __iomem *regs; 2588c2ecf20Sopenharmony_ci int irq; 2598c2ecf20Sopenharmony_ci struct clk *clk; 2608c2ecf20Sopenharmony_ci struct platform_device *pdev; 2618c2ecf20Sopenharmony_ci unsigned long spi_clk; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci struct spi_transfer *current_transfer; 2648c2ecf20Sopenharmony_ci int current_remaining_bytes; 2658c2ecf20Sopenharmony_ci int done_status; 2668c2ecf20Sopenharmony_ci dma_addr_t dma_addr_rx_bbuf; 2678c2ecf20Sopenharmony_ci dma_addr_t dma_addr_tx_bbuf; 2688c2ecf20Sopenharmony_ci void *addr_rx_bbuf; 2698c2ecf20Sopenharmony_ci void *addr_tx_bbuf; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci struct completion xfer_completion; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci struct atmel_spi_caps caps; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci bool use_dma; 2768c2ecf20Sopenharmony_ci bool use_pdc; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci bool keep_cs; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci u32 fifo_size; 2818c2ecf20Sopenharmony_ci u8 native_cs_free; 2828c2ecf20Sopenharmony_ci u8 native_cs_for_gpio; 2838c2ecf20Sopenharmony_ci}; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* Controller-specific per-slave state */ 2868c2ecf20Sopenharmony_cistruct atmel_spi_device { 2878c2ecf20Sopenharmony_ci u32 csr; 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci#define SPI_MAX_DMA_XFER 65535 /* true for both PDC and DMA */ 2918c2ecf20Sopenharmony_ci#define INVALID_DMA_ADDRESS 0xffffffff 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* 2948c2ecf20Sopenharmony_ci * Version 2 of the SPI controller has 2958c2ecf20Sopenharmony_ci * - CR.LASTXFER 2968c2ecf20Sopenharmony_ci * - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero) 2978c2ecf20Sopenharmony_ci * - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs) 2988c2ecf20Sopenharmony_ci * - SPI_CSRx.CSAAT 2998c2ecf20Sopenharmony_ci * - SPI_CSRx.SBCR allows faster clocking 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_cistatic bool atmel_spi_is_v2(struct atmel_spi *as) 3028c2ecf20Sopenharmony_ci{ 3038c2ecf20Sopenharmony_ci return as->caps.is_spi2; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* 3078c2ecf20Sopenharmony_ci * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby 3088c2ecf20Sopenharmony_ci * they assume that spi slave device state will not change on deselect, so 3098c2ecf20Sopenharmony_ci * that automagic deselection is OK. ("NPCSx rises if no data is to be 3108c2ecf20Sopenharmony_ci * transmitted") Not so! Workaround uses nCSx pins as GPIOs; or newer 3118c2ecf20Sopenharmony_ci * controllers have CSAAT and friends. 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Even controller newer than ar91rm9200, using GPIOs can make sens as 3148c2ecf20Sopenharmony_ci * it lets us support active-high chipselects despite the controller's 3158c2ecf20Sopenharmony_ci * belief that only active-low devices/systems exists. 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * However, at91rm9200 has a second erratum whereby nCS0 doesn't work 3188c2ecf20Sopenharmony_ci * right when driven with GPIO. ("Mode Fault does not allow more than one 3198c2ecf20Sopenharmony_ci * Master on Chip Select 0.") No workaround exists for that ... so for 3208c2ecf20Sopenharmony_ci * nCS0 on that chip, we (a) don't use the GPIO, (b) can't support CS_HIGH, 3218c2ecf20Sopenharmony_ci * and (c) will trigger that first erratum in some cases. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void cs_activate(struct atmel_spi *as, struct spi_device *spi) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci struct atmel_spi_device *asd = spi->controller_state; 3278c2ecf20Sopenharmony_ci int chip_select; 3288c2ecf20Sopenharmony_ci u32 mr; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (spi->cs_gpiod) 3318c2ecf20Sopenharmony_ci chip_select = as->native_cs_for_gpio; 3328c2ecf20Sopenharmony_ci else 3338c2ecf20Sopenharmony_ci chip_select = spi->chip_select; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (atmel_spi_is_v2(as)) { 3368c2ecf20Sopenharmony_ci spi_writel(as, CSR0 + 4 * chip_select, asd->csr); 3378c2ecf20Sopenharmony_ci /* For the low SPI version, there is a issue that PDC transfer 3388c2ecf20Sopenharmony_ci * on CS1,2,3 needs SPI_CSR0.BITS config as SPI_CSR1,2,3.BITS 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci spi_writel(as, CSR0, asd->csr); 3418c2ecf20Sopenharmony_ci if (as->caps.has_wdrbt) { 3428c2ecf20Sopenharmony_ci spi_writel(as, MR, 3438c2ecf20Sopenharmony_ci SPI_BF(PCS, ~(0x01 << chip_select)) 3448c2ecf20Sopenharmony_ci | SPI_BIT(WDRBT) 3458c2ecf20Sopenharmony_ci | SPI_BIT(MODFDIS) 3468c2ecf20Sopenharmony_ci | SPI_BIT(MSTR)); 3478c2ecf20Sopenharmony_ci } else { 3488c2ecf20Sopenharmony_ci spi_writel(as, MR, 3498c2ecf20Sopenharmony_ci SPI_BF(PCS, ~(0x01 << chip_select)) 3508c2ecf20Sopenharmony_ci | SPI_BIT(MODFDIS) 3518c2ecf20Sopenharmony_ci | SPI_BIT(MSTR)); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci mr = spi_readl(as, MR); 3558c2ecf20Sopenharmony_ci } else { 3568c2ecf20Sopenharmony_ci u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; 3578c2ecf20Sopenharmony_ci int i; 3588c2ecf20Sopenharmony_ci u32 csr; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* Make sure clock polarity is correct */ 3618c2ecf20Sopenharmony_ci for (i = 0; i < spi->master->num_chipselect; i++) { 3628c2ecf20Sopenharmony_ci csr = spi_readl(as, CSR0 + 4 * i); 3638c2ecf20Sopenharmony_ci if ((csr ^ cpol) & SPI_BIT(CPOL)) 3648c2ecf20Sopenharmony_ci spi_writel(as, CSR0 + 4 * i, 3658c2ecf20Sopenharmony_ci csr ^ SPI_BIT(CPOL)); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci mr = spi_readl(as, MR); 3698c2ecf20Sopenharmony_ci mr = SPI_BFINS(PCS, ~(1 << chip_select), mr); 3708c2ecf20Sopenharmony_ci spi_writel(as, MR, mr); 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "activate NPCS, mr %08x\n", mr); 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int chip_select; 3798c2ecf20Sopenharmony_ci u32 mr; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (spi->cs_gpiod) 3828c2ecf20Sopenharmony_ci chip_select = as->native_cs_for_gpio; 3838c2ecf20Sopenharmony_ci else 3848c2ecf20Sopenharmony_ci chip_select = spi->chip_select; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* only deactivate *this* device; sometimes transfers to 3878c2ecf20Sopenharmony_ci * another device may be active when this routine is called. 3888c2ecf20Sopenharmony_ci */ 3898c2ecf20Sopenharmony_ci mr = spi_readl(as, MR); 3908c2ecf20Sopenharmony_ci if (~SPI_BFEXT(PCS, mr) & (1 << chip_select)) { 3918c2ecf20Sopenharmony_ci mr = SPI_BFINS(PCS, 0xf, mr); 3928c2ecf20Sopenharmony_ci spi_writel(as, MR, mr); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "DEactivate NPCS, mr %08x\n", mr); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (!spi->cs_gpiod) 3988c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(LASTXFER)); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic void atmel_spi_lock(struct atmel_spi *as) __acquires(&as->lock) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci spin_lock_irqsave(&as->lock, as->flags); 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic void atmel_spi_unlock(struct atmel_spi *as) __releases(&as->lock) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&as->lock, as->flags); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic inline bool atmel_spi_is_vmalloc_xfer(struct spi_transfer *xfer) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci return is_vmalloc_addr(xfer->tx_buf) || is_vmalloc_addr(xfer->rx_buf); 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic inline bool atmel_spi_use_dma(struct atmel_spi *as, 4178c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 4188c2ecf20Sopenharmony_ci{ 4198c2ecf20Sopenharmony_ci return as->use_dma && xfer->len >= DMA_MIN_BYTES; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic bool atmel_spi_can_dma(struct spi_master *master, 4238c2ecf20Sopenharmony_ci struct spi_device *spi, 4248c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) 4298c2ecf20Sopenharmony_ci return atmel_spi_use_dma(as, xfer) && 4308c2ecf20Sopenharmony_ci !atmel_spi_is_vmalloc_xfer(xfer); 4318c2ecf20Sopenharmony_ci else 4328c2ecf20Sopenharmony_ci return atmel_spi_use_dma(as, xfer); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_cistatic int atmel_spi_dma_slave_config(struct atmel_spi *as, 4378c2ecf20Sopenharmony_ci struct dma_slave_config *slave_config, 4388c2ecf20Sopenharmony_ci u8 bits_per_word) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct spi_master *master = platform_get_drvdata(as->pdev); 4418c2ecf20Sopenharmony_ci int err = 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (bits_per_word > 8) { 4448c2ecf20Sopenharmony_ci slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 4458c2ecf20Sopenharmony_ci slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 4468c2ecf20Sopenharmony_ci } else { 4478c2ecf20Sopenharmony_ci slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 4488c2ecf20Sopenharmony_ci slave_config->src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci slave_config->dst_addr = (dma_addr_t)as->phybase + SPI_TDR; 4528c2ecf20Sopenharmony_ci slave_config->src_addr = (dma_addr_t)as->phybase + SPI_RDR; 4538c2ecf20Sopenharmony_ci slave_config->src_maxburst = 1; 4548c2ecf20Sopenharmony_ci slave_config->dst_maxburst = 1; 4558c2ecf20Sopenharmony_ci slave_config->device_fc = false; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* 4588c2ecf20Sopenharmony_ci * This driver uses fixed peripheral select mode (PS bit set to '0' in 4598c2ecf20Sopenharmony_ci * the Mode Register). 4608c2ecf20Sopenharmony_ci * So according to the datasheet, when FIFOs are available (and 4618c2ecf20Sopenharmony_ci * enabled), the Transmit FIFO operates in Multiple Data Mode. 4628c2ecf20Sopenharmony_ci * In this mode, up to 2 data, not 4, can be written into the Transmit 4638c2ecf20Sopenharmony_ci * Data Register in a single access. 4648c2ecf20Sopenharmony_ci * However, the first data has to be written into the lowest 16 bits and 4658c2ecf20Sopenharmony_ci * the second data into the highest 16 bits of the Transmit 4668c2ecf20Sopenharmony_ci * Data Register. For 8bit data (the most frequent case), it would 4678c2ecf20Sopenharmony_ci * require to rework tx_buf so each data would actualy fit 16 bits. 4688c2ecf20Sopenharmony_ci * So we'd rather write only one data at the time. Hence the transmit 4698c2ecf20Sopenharmony_ci * path works the same whether FIFOs are available (and enabled) or not. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_ci slave_config->direction = DMA_MEM_TO_DEV; 4728c2ecf20Sopenharmony_ci if (dmaengine_slave_config(master->dma_tx, slave_config)) { 4738c2ecf20Sopenharmony_ci dev_err(&as->pdev->dev, 4748c2ecf20Sopenharmony_ci "failed to configure tx dma channel\n"); 4758c2ecf20Sopenharmony_ci err = -EINVAL; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* 4798c2ecf20Sopenharmony_ci * This driver configures the spi controller for master mode (MSTR bit 4808c2ecf20Sopenharmony_ci * set to '1' in the Mode Register). 4818c2ecf20Sopenharmony_ci * So according to the datasheet, when FIFOs are available (and 4828c2ecf20Sopenharmony_ci * enabled), the Receive FIFO operates in Single Data Mode. 4838c2ecf20Sopenharmony_ci * So the receive path works the same whether FIFOs are available (and 4848c2ecf20Sopenharmony_ci * enabled) or not. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ci slave_config->direction = DMA_DEV_TO_MEM; 4878c2ecf20Sopenharmony_ci if (dmaengine_slave_config(master->dma_rx, slave_config)) { 4888c2ecf20Sopenharmony_ci dev_err(&as->pdev->dev, 4898c2ecf20Sopenharmony_ci "failed to configure rx dma channel\n"); 4908c2ecf20Sopenharmony_ci err = -EINVAL; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return err; 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int atmel_spi_configure_dma(struct spi_master *master, 4978c2ecf20Sopenharmony_ci struct atmel_spi *as) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci struct dma_slave_config slave_config; 5008c2ecf20Sopenharmony_ci struct device *dev = &as->pdev->dev; 5018c2ecf20Sopenharmony_ci int err; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci dma_cap_mask_t mask; 5048c2ecf20Sopenharmony_ci dma_cap_zero(mask); 5058c2ecf20Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci master->dma_tx = dma_request_chan(dev, "tx"); 5088c2ecf20Sopenharmony_ci if (IS_ERR(master->dma_tx)) { 5098c2ecf20Sopenharmony_ci err = dev_err_probe(dev, PTR_ERR(master->dma_tx), 5108c2ecf20Sopenharmony_ci "No TX DMA channel, DMA is disabled\n"); 5118c2ecf20Sopenharmony_ci goto error_clear; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci master->dma_rx = dma_request_chan(dev, "rx"); 5158c2ecf20Sopenharmony_ci if (IS_ERR(master->dma_rx)) { 5168c2ecf20Sopenharmony_ci err = PTR_ERR(master->dma_rx); 5178c2ecf20Sopenharmony_ci /* 5188c2ecf20Sopenharmony_ci * No reason to check EPROBE_DEFER here since we have already 5198c2ecf20Sopenharmony_ci * requested tx channel. 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci dev_err(dev, "No RX DMA channel, DMA is disabled\n"); 5228c2ecf20Sopenharmony_ci goto error; 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci err = atmel_spi_dma_slave_config(as, &slave_config, 8); 5268c2ecf20Sopenharmony_ci if (err) 5278c2ecf20Sopenharmony_ci goto error; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci dev_info(&as->pdev->dev, 5308c2ecf20Sopenharmony_ci "Using %s (tx) and %s (rx) for DMA transfers\n", 5318c2ecf20Sopenharmony_ci dma_chan_name(master->dma_tx), 5328c2ecf20Sopenharmony_ci dma_chan_name(master->dma_rx)); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return 0; 5358c2ecf20Sopenharmony_cierror: 5368c2ecf20Sopenharmony_ci if (!IS_ERR(master->dma_rx)) 5378c2ecf20Sopenharmony_ci dma_release_channel(master->dma_rx); 5388c2ecf20Sopenharmony_ci if (!IS_ERR(master->dma_tx)) 5398c2ecf20Sopenharmony_ci dma_release_channel(master->dma_tx); 5408c2ecf20Sopenharmony_cierror_clear: 5418c2ecf20Sopenharmony_ci master->dma_tx = master->dma_rx = NULL; 5428c2ecf20Sopenharmony_ci return err; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic void atmel_spi_stop_dma(struct spi_master *master) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci if (master->dma_rx) 5488c2ecf20Sopenharmony_ci dmaengine_terminate_all(master->dma_rx); 5498c2ecf20Sopenharmony_ci if (master->dma_tx) 5508c2ecf20Sopenharmony_ci dmaengine_terminate_all(master->dma_tx); 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic void atmel_spi_release_dma(struct spi_master *master) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci if (master->dma_rx) { 5568c2ecf20Sopenharmony_ci dma_release_channel(master->dma_rx); 5578c2ecf20Sopenharmony_ci master->dma_rx = NULL; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci if (master->dma_tx) { 5608c2ecf20Sopenharmony_ci dma_release_channel(master->dma_tx); 5618c2ecf20Sopenharmony_ci master->dma_tx = NULL; 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci/* This function is called by the DMA driver from tasklet context */ 5668c2ecf20Sopenharmony_cistatic void dma_callback(void *data) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct spi_master *master = data; 5698c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (is_vmalloc_addr(as->current_transfer->rx_buf) && 5728c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { 5738c2ecf20Sopenharmony_ci memcpy(as->current_transfer->rx_buf, as->addr_rx_bbuf, 5748c2ecf20Sopenharmony_ci as->current_transfer->len); 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci complete(&as->xfer_completion); 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci/* 5808c2ecf20Sopenharmony_ci * Next transfer using PIO without FIFO. 5818c2ecf20Sopenharmony_ci */ 5828c2ecf20Sopenharmony_cistatic void atmel_spi_next_xfer_single(struct spi_master *master, 5838c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 5868c2ecf20Sopenharmony_ci unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_pio\n"); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* Make sure data is not remaining in RDR */ 5918c2ecf20Sopenharmony_ci spi_readl(as, RDR); 5928c2ecf20Sopenharmony_ci while (spi_readl(as, SR) & SPI_BIT(RDRF)) { 5938c2ecf20Sopenharmony_ci spi_readl(as, RDR); 5948c2ecf20Sopenharmony_ci cpu_relax(); 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) 5988c2ecf20Sopenharmony_ci spi_writel(as, TDR, *(u16 *)(xfer->tx_buf + xfer_pos)); 5998c2ecf20Sopenharmony_ci else 6008c2ecf20Sopenharmony_ci spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos)); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci dev_dbg(master->dev.parent, 6038c2ecf20Sopenharmony_ci " start pio xfer %p: len %u tx %p rx %p bitpw %d\n", 6048c2ecf20Sopenharmony_ci xfer, xfer->len, xfer->tx_buf, xfer->rx_buf, 6058c2ecf20Sopenharmony_ci xfer->bits_per_word); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Enable relevant interrupts */ 6088c2ecf20Sopenharmony_ci spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES)); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci/* 6128c2ecf20Sopenharmony_ci * Next transfer using PIO with FIFO. 6138c2ecf20Sopenharmony_ci */ 6148c2ecf20Sopenharmony_cistatic void atmel_spi_next_xfer_fifo(struct spi_master *master, 6158c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 6188c2ecf20Sopenharmony_ci u32 current_remaining_data, num_data; 6198c2ecf20Sopenharmony_ci u32 offset = xfer->len - as->current_remaining_bytes; 6208c2ecf20Sopenharmony_ci const u16 *words = (const u16 *)((u8 *)xfer->tx_buf + offset); 6218c2ecf20Sopenharmony_ci const u8 *bytes = (const u8 *)((u8 *)xfer->tx_buf + offset); 6228c2ecf20Sopenharmony_ci u16 td0, td1; 6238c2ecf20Sopenharmony_ci u32 fifomr; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_fifo\n"); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci /* Compute the number of data to transfer in the current iteration */ 6288c2ecf20Sopenharmony_ci current_remaining_data = ((xfer->bits_per_word > 8) ? 6298c2ecf20Sopenharmony_ci ((u32)as->current_remaining_bytes >> 1) : 6308c2ecf20Sopenharmony_ci (u32)as->current_remaining_bytes); 6318c2ecf20Sopenharmony_ci num_data = min(current_remaining_data, as->fifo_size); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* Flush RX and TX FIFOs */ 6348c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(RXFCLR) | SPI_BIT(TXFCLR)); 6358c2ecf20Sopenharmony_ci while (spi_readl(as, FLR)) 6368c2ecf20Sopenharmony_ci cpu_relax(); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci /* Set RX FIFO Threshold to the number of data to transfer */ 6398c2ecf20Sopenharmony_ci fifomr = spi_readl(as, FMR); 6408c2ecf20Sopenharmony_ci spi_writel(as, FMR, SPI_BFINS(RXFTHRES, num_data, fifomr)); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /* Clear FIFO flags in the Status Register, especially RXFTHF */ 6438c2ecf20Sopenharmony_ci (void)spi_readl(as, SR); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci /* Fill TX FIFO */ 6468c2ecf20Sopenharmony_ci while (num_data >= 2) { 6478c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) { 6488c2ecf20Sopenharmony_ci td0 = *words++; 6498c2ecf20Sopenharmony_ci td1 = *words++; 6508c2ecf20Sopenharmony_ci } else { 6518c2ecf20Sopenharmony_ci td0 = *bytes++; 6528c2ecf20Sopenharmony_ci td1 = *bytes++; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci spi_writel(as, TDR, (td1 << 16) | td0); 6568c2ecf20Sopenharmony_ci num_data -= 2; 6578c2ecf20Sopenharmony_ci } 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci if (num_data) { 6608c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) 6618c2ecf20Sopenharmony_ci td0 = *words++; 6628c2ecf20Sopenharmony_ci else 6638c2ecf20Sopenharmony_ci td0 = *bytes++; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci spi_writew(as, TDR, td0); 6668c2ecf20Sopenharmony_ci num_data--; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci dev_dbg(master->dev.parent, 6708c2ecf20Sopenharmony_ci " start fifo xfer %p: len %u tx %p rx %p bitpw %d\n", 6718c2ecf20Sopenharmony_ci xfer, xfer->len, xfer->tx_buf, xfer->rx_buf, 6728c2ecf20Sopenharmony_ci xfer->bits_per_word); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * Enable RX FIFO Threshold Flag interrupt to be notified about 6768c2ecf20Sopenharmony_ci * transfer completion. 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci spi_writel(as, IER, SPI_BIT(RXFTHF) | SPI_BIT(OVRES)); 6798c2ecf20Sopenharmony_ci} 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci/* 6828c2ecf20Sopenharmony_ci * Next transfer using PIO. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_cistatic void atmel_spi_next_xfer_pio(struct spi_master *master, 6858c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (as->fifo_size) 6908c2ecf20Sopenharmony_ci atmel_spi_next_xfer_fifo(master, xfer); 6918c2ecf20Sopenharmony_ci else 6928c2ecf20Sopenharmony_ci atmel_spi_next_xfer_single(master, xfer); 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci/* 6968c2ecf20Sopenharmony_ci * Submit next transfer for DMA. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_cistatic int atmel_spi_next_xfer_dma_submit(struct spi_master *master, 6998c2ecf20Sopenharmony_ci struct spi_transfer *xfer, 7008c2ecf20Sopenharmony_ci u32 *plen) 7018c2ecf20Sopenharmony_ci __must_hold(&as->lock) 7028c2ecf20Sopenharmony_ci{ 7038c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 7048c2ecf20Sopenharmony_ci struct dma_chan *rxchan = master->dma_rx; 7058c2ecf20Sopenharmony_ci struct dma_chan *txchan = master->dma_tx; 7068c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc; 7078c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *txdesc; 7088c2ecf20Sopenharmony_ci struct dma_slave_config slave_config; 7098c2ecf20Sopenharmony_ci dma_cookie_t cookie; 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_dma_submit\n"); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* Check that the channels are available */ 7148c2ecf20Sopenharmony_ci if (!rxchan || !txchan) 7158c2ecf20Sopenharmony_ci return -ENODEV; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* release lock for DMA operations */ 7188c2ecf20Sopenharmony_ci atmel_spi_unlock(as); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci *plen = xfer->len; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (atmel_spi_dma_slave_config(as, &slave_config, 7238c2ecf20Sopenharmony_ci xfer->bits_per_word)) 7248c2ecf20Sopenharmony_ci goto err_exit; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Send both scatterlists */ 7278c2ecf20Sopenharmony_ci if (atmel_spi_is_vmalloc_xfer(xfer) && 7288c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { 7298c2ecf20Sopenharmony_ci rxdesc = dmaengine_prep_slave_single(rxchan, 7308c2ecf20Sopenharmony_ci as->dma_addr_rx_bbuf, 7318c2ecf20Sopenharmony_ci xfer->len, 7328c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 7338c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | 7348c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 7358c2ecf20Sopenharmony_ci } else { 7368c2ecf20Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg(rxchan, 7378c2ecf20Sopenharmony_ci xfer->rx_sg.sgl, 7388c2ecf20Sopenharmony_ci xfer->rx_sg.nents, 7398c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 7408c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | 7418c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 7428c2ecf20Sopenharmony_ci } 7438c2ecf20Sopenharmony_ci if (!rxdesc) 7448c2ecf20Sopenharmony_ci goto err_dma; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (atmel_spi_is_vmalloc_xfer(xfer) && 7478c2ecf20Sopenharmony_ci IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { 7488c2ecf20Sopenharmony_ci memcpy(as->addr_tx_bbuf, xfer->tx_buf, xfer->len); 7498c2ecf20Sopenharmony_ci txdesc = dmaengine_prep_slave_single(txchan, 7508c2ecf20Sopenharmony_ci as->dma_addr_tx_bbuf, 7518c2ecf20Sopenharmony_ci xfer->len, DMA_MEM_TO_DEV, 7528c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | 7538c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 7548c2ecf20Sopenharmony_ci } else { 7558c2ecf20Sopenharmony_ci txdesc = dmaengine_prep_slave_sg(txchan, 7568c2ecf20Sopenharmony_ci xfer->tx_sg.sgl, 7578c2ecf20Sopenharmony_ci xfer->tx_sg.nents, 7588c2ecf20Sopenharmony_ci DMA_MEM_TO_DEV, 7598c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | 7608c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci if (!txdesc) 7638c2ecf20Sopenharmony_ci goto err_dma; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci dev_dbg(master->dev.parent, 7668c2ecf20Sopenharmony_ci " start dma xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", 7678c2ecf20Sopenharmony_ci xfer, xfer->len, xfer->tx_buf, (unsigned long long)xfer->tx_dma, 7688c2ecf20Sopenharmony_ci xfer->rx_buf, (unsigned long long)xfer->rx_dma); 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Enable relevant interrupts */ 7718c2ecf20Sopenharmony_ci spi_writel(as, IER, SPI_BIT(OVRES)); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* Put the callback on the RX transfer only, that should finish last */ 7748c2ecf20Sopenharmony_ci rxdesc->callback = dma_callback; 7758c2ecf20Sopenharmony_ci rxdesc->callback_param = master; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci /* Submit and fire RX and TX with TX last so we're ready to read! */ 7788c2ecf20Sopenharmony_ci cookie = rxdesc->tx_submit(rxdesc); 7798c2ecf20Sopenharmony_ci if (dma_submit_error(cookie)) 7808c2ecf20Sopenharmony_ci goto err_dma; 7818c2ecf20Sopenharmony_ci cookie = txdesc->tx_submit(txdesc); 7828c2ecf20Sopenharmony_ci if (dma_submit_error(cookie)) 7838c2ecf20Sopenharmony_ci goto err_dma; 7848c2ecf20Sopenharmony_ci rxchan->device->device_issue_pending(rxchan); 7858c2ecf20Sopenharmony_ci txchan->device->device_issue_pending(txchan); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci /* take back lock */ 7888c2ecf20Sopenharmony_ci atmel_spi_lock(as); 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cierr_dma: 7928c2ecf20Sopenharmony_ci spi_writel(as, IDR, SPI_BIT(OVRES)); 7938c2ecf20Sopenharmony_ci atmel_spi_stop_dma(master); 7948c2ecf20Sopenharmony_cierr_exit: 7958c2ecf20Sopenharmony_ci atmel_spi_lock(as); 7968c2ecf20Sopenharmony_ci return -ENOMEM; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic void atmel_spi_next_xfer_data(struct spi_master *master, 8008c2ecf20Sopenharmony_ci struct spi_transfer *xfer, 8018c2ecf20Sopenharmony_ci dma_addr_t *tx_dma, 8028c2ecf20Sopenharmony_ci dma_addr_t *rx_dma, 8038c2ecf20Sopenharmony_ci u32 *plen) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci *rx_dma = xfer->rx_dma + xfer->len - *plen; 8068c2ecf20Sopenharmony_ci *tx_dma = xfer->tx_dma + xfer->len - *plen; 8078c2ecf20Sopenharmony_ci if (*plen > master->max_dma_len) 8088c2ecf20Sopenharmony_ci *plen = master->max_dma_len; 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int atmel_spi_set_xfer_speed(struct atmel_spi *as, 8128c2ecf20Sopenharmony_ci struct spi_device *spi, 8138c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 8148c2ecf20Sopenharmony_ci{ 8158c2ecf20Sopenharmony_ci u32 scbr, csr; 8168c2ecf20Sopenharmony_ci unsigned long bus_hz; 8178c2ecf20Sopenharmony_ci int chip_select; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (spi->cs_gpiod) 8208c2ecf20Sopenharmony_ci chip_select = as->native_cs_for_gpio; 8218c2ecf20Sopenharmony_ci else 8228c2ecf20Sopenharmony_ci chip_select = spi->chip_select; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci /* v1 chips start out at half the peripheral bus speed. */ 8258c2ecf20Sopenharmony_ci bus_hz = as->spi_clk; 8268c2ecf20Sopenharmony_ci if (!atmel_spi_is_v2(as)) 8278c2ecf20Sopenharmony_ci bus_hz /= 2; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci /* 8308c2ecf20Sopenharmony_ci * Calculate the lowest divider that satisfies the 8318c2ecf20Sopenharmony_ci * constraint, assuming div32/fdiv/mbz == 0. 8328c2ecf20Sopenharmony_ci */ 8338c2ecf20Sopenharmony_ci scbr = DIV_ROUND_UP(bus_hz, xfer->speed_hz); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * If the resulting divider doesn't fit into the 8378c2ecf20Sopenharmony_ci * register bitfield, we can't satisfy the constraint. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci if (scbr >= (1 << SPI_SCBR_SIZE)) { 8408c2ecf20Sopenharmony_ci dev_err(&spi->dev, 8418c2ecf20Sopenharmony_ci "setup: %d Hz too slow, scbr %u; min %ld Hz\n", 8428c2ecf20Sopenharmony_ci xfer->speed_hz, scbr, bus_hz/255); 8438c2ecf20Sopenharmony_ci return -EINVAL; 8448c2ecf20Sopenharmony_ci } 8458c2ecf20Sopenharmony_ci if (scbr == 0) { 8468c2ecf20Sopenharmony_ci dev_err(&spi->dev, 8478c2ecf20Sopenharmony_ci "setup: %d Hz too high, scbr %u; max %ld Hz\n", 8488c2ecf20Sopenharmony_ci xfer->speed_hz, scbr, bus_hz); 8498c2ecf20Sopenharmony_ci return -EINVAL; 8508c2ecf20Sopenharmony_ci } 8518c2ecf20Sopenharmony_ci csr = spi_readl(as, CSR0 + 4 * chip_select); 8528c2ecf20Sopenharmony_ci csr = SPI_BFINS(SCBR, scbr, csr); 8538c2ecf20Sopenharmony_ci spi_writel(as, CSR0 + 4 * chip_select, csr); 8548c2ecf20Sopenharmony_ci xfer->effective_speed_hz = bus_hz / scbr; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci return 0; 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci/* 8608c2ecf20Sopenharmony_ci * Submit next transfer for PDC. 8618c2ecf20Sopenharmony_ci * lock is held, spi irq is blocked 8628c2ecf20Sopenharmony_ci */ 8638c2ecf20Sopenharmony_cistatic void atmel_spi_pdc_next_xfer(struct spi_master *master, 8648c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 8678c2ecf20Sopenharmony_ci u32 len; 8688c2ecf20Sopenharmony_ci dma_addr_t tx_dma, rx_dma; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci len = as->current_remaining_bytes; 8738c2ecf20Sopenharmony_ci atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); 8748c2ecf20Sopenharmony_ci as->current_remaining_bytes -= len; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci spi_writel(as, RPR, rx_dma); 8778c2ecf20Sopenharmony_ci spi_writel(as, TPR, tx_dma); 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) 8808c2ecf20Sopenharmony_ci len >>= 1; 8818c2ecf20Sopenharmony_ci spi_writel(as, RCR, len); 8828c2ecf20Sopenharmony_ci spi_writel(as, TCR, len); 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci dev_dbg(&master->dev, 8858c2ecf20Sopenharmony_ci " start xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", 8868c2ecf20Sopenharmony_ci xfer, xfer->len, xfer->tx_buf, 8878c2ecf20Sopenharmony_ci (unsigned long long)xfer->tx_dma, xfer->rx_buf, 8888c2ecf20Sopenharmony_ci (unsigned long long)xfer->rx_dma); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (as->current_remaining_bytes) { 8918c2ecf20Sopenharmony_ci len = as->current_remaining_bytes; 8928c2ecf20Sopenharmony_ci atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); 8938c2ecf20Sopenharmony_ci as->current_remaining_bytes -= len; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci spi_writel(as, RNPR, rx_dma); 8968c2ecf20Sopenharmony_ci spi_writel(as, TNPR, tx_dma); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) 8998c2ecf20Sopenharmony_ci len >>= 1; 9008c2ecf20Sopenharmony_ci spi_writel(as, RNCR, len); 9018c2ecf20Sopenharmony_ci spi_writel(as, TNCR, len); 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci dev_dbg(&master->dev, 9048c2ecf20Sopenharmony_ci " next xfer %p: len %u tx %p/%08llx rx %p/%08llx\n", 9058c2ecf20Sopenharmony_ci xfer, xfer->len, xfer->tx_buf, 9068c2ecf20Sopenharmony_ci (unsigned long long)xfer->tx_dma, xfer->rx_buf, 9078c2ecf20Sopenharmony_ci (unsigned long long)xfer->rx_dma); 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* REVISIT: We're waiting for RXBUFF before we start the next 9118c2ecf20Sopenharmony_ci * transfer because we need to handle some difficult timing 9128c2ecf20Sopenharmony_ci * issues otherwise. If we wait for TXBUFE in one transfer and 9138c2ecf20Sopenharmony_ci * then starts waiting for RXBUFF in the next, it's difficult 9148c2ecf20Sopenharmony_ci * to tell the difference between the RXBUFF interrupt we're 9158c2ecf20Sopenharmony_ci * actually waiting for and the RXBUFF interrupt of the 9168c2ecf20Sopenharmony_ci * previous transfer. 9178c2ecf20Sopenharmony_ci * 9188c2ecf20Sopenharmony_ci * It should be doable, though. Just not now... 9198c2ecf20Sopenharmony_ci */ 9208c2ecf20Sopenharmony_ci spi_writel(as, IER, SPI_BIT(RXBUFF) | SPI_BIT(OVRES)); 9218c2ecf20Sopenharmony_ci spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci/* 9258c2ecf20Sopenharmony_ci * For DMA, tx_buf/tx_dma have the same relationship as rx_buf/rx_dma: 9268c2ecf20Sopenharmony_ci * - The buffer is either valid for CPU access, else NULL 9278c2ecf20Sopenharmony_ci * - If the buffer is valid, so is its DMA address 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * This driver manages the dma address unless message->is_dma_mapped. 9308c2ecf20Sopenharmony_ci */ 9318c2ecf20Sopenharmony_cistatic int 9328c2ecf20Sopenharmony_ciatmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci struct device *dev = &as->pdev->dev; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS; 9378c2ecf20Sopenharmony_ci if (xfer->tx_buf) { 9388c2ecf20Sopenharmony_ci /* tx_buf is a const void* where we need a void * for the dma 9398c2ecf20Sopenharmony_ci * mapping */ 9408c2ecf20Sopenharmony_ci void *nonconst_tx = (void *)xfer->tx_buf; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci xfer->tx_dma = dma_map_single(dev, 9438c2ecf20Sopenharmony_ci nonconst_tx, xfer->len, 9448c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9458c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, xfer->tx_dma)) 9468c2ecf20Sopenharmony_ci return -ENOMEM; 9478c2ecf20Sopenharmony_ci } 9488c2ecf20Sopenharmony_ci if (xfer->rx_buf) { 9498c2ecf20Sopenharmony_ci xfer->rx_dma = dma_map_single(dev, 9508c2ecf20Sopenharmony_ci xfer->rx_buf, xfer->len, 9518c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 9528c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, xfer->rx_dma)) { 9538c2ecf20Sopenharmony_ci if (xfer->tx_buf) 9548c2ecf20Sopenharmony_ci dma_unmap_single(dev, 9558c2ecf20Sopenharmony_ci xfer->tx_dma, xfer->len, 9568c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 9578c2ecf20Sopenharmony_ci return -ENOMEM; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci return 0; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic void atmel_spi_dma_unmap_xfer(struct spi_master *master, 9648c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci if (xfer->tx_dma != INVALID_DMA_ADDRESS) 9678c2ecf20Sopenharmony_ci dma_unmap_single(master->dev.parent, xfer->tx_dma, 9688c2ecf20Sopenharmony_ci xfer->len, DMA_TO_DEVICE); 9698c2ecf20Sopenharmony_ci if (xfer->rx_dma != INVALID_DMA_ADDRESS) 9708c2ecf20Sopenharmony_ci dma_unmap_single(master->dev.parent, xfer->rx_dma, 9718c2ecf20Sopenharmony_ci xfer->len, DMA_FROM_DEVICE); 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_cistatic void atmel_spi_disable_pdc_transfer(struct atmel_spi *as) 9758c2ecf20Sopenharmony_ci{ 9768c2ecf20Sopenharmony_ci spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic void 9808c2ecf20Sopenharmony_ciatmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer) 9818c2ecf20Sopenharmony_ci{ 9828c2ecf20Sopenharmony_ci u8 *rxp; 9838c2ecf20Sopenharmony_ci u16 *rxp16; 9848c2ecf20Sopenharmony_ci unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) { 9878c2ecf20Sopenharmony_ci rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos); 9888c2ecf20Sopenharmony_ci *rxp16 = spi_readl(as, RDR); 9898c2ecf20Sopenharmony_ci } else { 9908c2ecf20Sopenharmony_ci rxp = ((u8 *)xfer->rx_buf) + xfer_pos; 9918c2ecf20Sopenharmony_ci *rxp = spi_readl(as, RDR); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) { 9948c2ecf20Sopenharmony_ci if (as->current_remaining_bytes > 2) 9958c2ecf20Sopenharmony_ci as->current_remaining_bytes -= 2; 9968c2ecf20Sopenharmony_ci else 9978c2ecf20Sopenharmony_ci as->current_remaining_bytes = 0; 9988c2ecf20Sopenharmony_ci } else { 9998c2ecf20Sopenharmony_ci as->current_remaining_bytes--; 10008c2ecf20Sopenharmony_ci } 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic void 10048c2ecf20Sopenharmony_ciatmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci u32 fifolr = spi_readl(as, FLR); 10078c2ecf20Sopenharmony_ci u32 num_bytes, num_data = SPI_BFEXT(RXFL, fifolr); 10088c2ecf20Sopenharmony_ci u32 offset = xfer->len - as->current_remaining_bytes; 10098c2ecf20Sopenharmony_ci u16 *words = (u16 *)((u8 *)xfer->rx_buf + offset); 10108c2ecf20Sopenharmony_ci u8 *bytes = (u8 *)((u8 *)xfer->rx_buf + offset); 10118c2ecf20Sopenharmony_ci u16 rd; /* RD field is the lowest 16 bits of RDR */ 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci /* Update the number of remaining bytes to transfer */ 10148c2ecf20Sopenharmony_ci num_bytes = ((xfer->bits_per_word > 8) ? 10158c2ecf20Sopenharmony_ci (num_data << 1) : 10168c2ecf20Sopenharmony_ci num_data); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci if (as->current_remaining_bytes > num_bytes) 10198c2ecf20Sopenharmony_ci as->current_remaining_bytes -= num_bytes; 10208c2ecf20Sopenharmony_ci else 10218c2ecf20Sopenharmony_ci as->current_remaining_bytes = 0; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci /* Handle odd number of bytes when data are more than 8bit width */ 10248c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) 10258c2ecf20Sopenharmony_ci as->current_remaining_bytes &= ~0x1; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* Read data */ 10288c2ecf20Sopenharmony_ci while (num_data) { 10298c2ecf20Sopenharmony_ci rd = spi_readl(as, RDR); 10308c2ecf20Sopenharmony_ci if (xfer->bits_per_word > 8) 10318c2ecf20Sopenharmony_ci *words++ = rd; 10328c2ecf20Sopenharmony_ci else 10338c2ecf20Sopenharmony_ci *bytes++ = rd; 10348c2ecf20Sopenharmony_ci num_data--; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci/* Called from IRQ 10398c2ecf20Sopenharmony_ci * 10408c2ecf20Sopenharmony_ci * Must update "current_remaining_bytes" to keep track of data 10418c2ecf20Sopenharmony_ci * to transfer. 10428c2ecf20Sopenharmony_ci */ 10438c2ecf20Sopenharmony_cistatic void 10448c2ecf20Sopenharmony_ciatmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) 10458c2ecf20Sopenharmony_ci{ 10468c2ecf20Sopenharmony_ci if (as->fifo_size) 10478c2ecf20Sopenharmony_ci atmel_spi_pump_fifo_data(as, xfer); 10488c2ecf20Sopenharmony_ci else 10498c2ecf20Sopenharmony_ci atmel_spi_pump_single_data(as, xfer); 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci/* Interrupt 10538c2ecf20Sopenharmony_ci * 10548c2ecf20Sopenharmony_ci * No need for locking in this Interrupt handler: done_status is the 10558c2ecf20Sopenharmony_ci * only information modified. 10568c2ecf20Sopenharmony_ci */ 10578c2ecf20Sopenharmony_cistatic irqreturn_t 10588c2ecf20Sopenharmony_ciatmel_spi_pio_interrupt(int irq, void *dev_id) 10598c2ecf20Sopenharmony_ci{ 10608c2ecf20Sopenharmony_ci struct spi_master *master = dev_id; 10618c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 10628c2ecf20Sopenharmony_ci u32 status, pending, imr; 10638c2ecf20Sopenharmony_ci struct spi_transfer *xfer; 10648c2ecf20Sopenharmony_ci int ret = IRQ_NONE; 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci imr = spi_readl(as, IMR); 10678c2ecf20Sopenharmony_ci status = spi_readl(as, SR); 10688c2ecf20Sopenharmony_ci pending = status & imr; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci if (pending & SPI_BIT(OVRES)) { 10718c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 10728c2ecf20Sopenharmony_ci spi_writel(as, IDR, SPI_BIT(OVRES)); 10738c2ecf20Sopenharmony_ci dev_warn(master->dev.parent, "overrun\n"); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* 10768c2ecf20Sopenharmony_ci * When we get an overrun, we disregard the current 10778c2ecf20Sopenharmony_ci * transfer. Data will not be copied back from any 10788c2ecf20Sopenharmony_ci * bounce buffer and msg->actual_len will not be 10798c2ecf20Sopenharmony_ci * updated with the last xfer. 10808c2ecf20Sopenharmony_ci * 10818c2ecf20Sopenharmony_ci * We will also not process any remaning transfers in 10828c2ecf20Sopenharmony_ci * the message. 10838c2ecf20Sopenharmony_ci */ 10848c2ecf20Sopenharmony_ci as->done_status = -EIO; 10858c2ecf20Sopenharmony_ci smp_wmb(); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci /* Clear any overrun happening while cleaning up */ 10888c2ecf20Sopenharmony_ci spi_readl(as, SR); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci complete(&as->xfer_completion); 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci } else if (pending & (SPI_BIT(RDRF) | SPI_BIT(RXFTHF))) { 10938c2ecf20Sopenharmony_ci atmel_spi_lock(as); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci if (as->current_remaining_bytes) { 10968c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 10978c2ecf20Sopenharmony_ci xfer = as->current_transfer; 10988c2ecf20Sopenharmony_ci atmel_spi_pump_pio_data(as, xfer); 10998c2ecf20Sopenharmony_ci if (!as->current_remaining_bytes) 11008c2ecf20Sopenharmony_ci spi_writel(as, IDR, pending); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci complete(&as->xfer_completion); 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci atmel_spi_unlock(as); 11068c2ecf20Sopenharmony_ci } else { 11078c2ecf20Sopenharmony_ci WARN_ONCE(pending, "IRQ not handled, pending = %x\n", pending); 11088c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 11098c2ecf20Sopenharmony_ci spi_writel(as, IDR, pending); 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci return ret; 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic irqreturn_t 11168c2ecf20Sopenharmony_ciatmel_spi_pdc_interrupt(int irq, void *dev_id) 11178c2ecf20Sopenharmony_ci{ 11188c2ecf20Sopenharmony_ci struct spi_master *master = dev_id; 11198c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 11208c2ecf20Sopenharmony_ci u32 status, pending, imr; 11218c2ecf20Sopenharmony_ci int ret = IRQ_NONE; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci imr = spi_readl(as, IMR); 11248c2ecf20Sopenharmony_ci status = spi_readl(as, SR); 11258c2ecf20Sopenharmony_ci pending = status & imr; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci if (pending & SPI_BIT(OVRES)) { 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci spi_writel(as, IDR, (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX) 11328c2ecf20Sopenharmony_ci | SPI_BIT(OVRES))); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci /* Clear any overrun happening while cleaning up */ 11358c2ecf20Sopenharmony_ci spi_readl(as, SR); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci as->done_status = -EIO; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci complete(&as->xfer_completion); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci } else if (pending & (SPI_BIT(RXBUFF) | SPI_BIT(ENDRX))) { 11428c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci spi_writel(as, IDR, pending); 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci complete(&as->xfer_completion); 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci return ret; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistatic int atmel_word_delay_csr(struct spi_device *spi, struct atmel_spi *as) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci struct spi_delay *delay = &spi->word_delay; 11558c2ecf20Sopenharmony_ci u32 value = delay->value; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci switch (delay->unit) { 11588c2ecf20Sopenharmony_ci case SPI_DELAY_UNIT_NSECS: 11598c2ecf20Sopenharmony_ci value /= 1000; 11608c2ecf20Sopenharmony_ci break; 11618c2ecf20Sopenharmony_ci case SPI_DELAY_UNIT_USECS: 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci default: 11648c2ecf20Sopenharmony_ci return -EINVAL; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return (as->spi_clk / 1000000 * value) >> 5; 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_cistatic void initialize_native_cs_for_gpio(struct atmel_spi *as) 11718c2ecf20Sopenharmony_ci{ 11728c2ecf20Sopenharmony_ci int i; 11738c2ecf20Sopenharmony_ci struct spi_master *master = platform_get_drvdata(as->pdev); 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci if (!as->native_cs_free) 11768c2ecf20Sopenharmony_ci return; /* already initialized */ 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci if (!master->cs_gpiods) 11798c2ecf20Sopenharmony_ci return; /* No CS GPIO */ 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci /* 11828c2ecf20Sopenharmony_ci * On the first version of the controller (AT91RM9200), CS0 11838c2ecf20Sopenharmony_ci * can't be used associated with GPIO 11848c2ecf20Sopenharmony_ci */ 11858c2ecf20Sopenharmony_ci if (atmel_spi_is_v2(as)) 11868c2ecf20Sopenharmony_ci i = 0; 11878c2ecf20Sopenharmony_ci else 11888c2ecf20Sopenharmony_ci i = 1; 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci for (; i < 4; i++) 11918c2ecf20Sopenharmony_ci if (master->cs_gpiods[i]) 11928c2ecf20Sopenharmony_ci as->native_cs_free |= BIT(i); 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci if (as->native_cs_free) 11958c2ecf20Sopenharmony_ci as->native_cs_for_gpio = ffs(as->native_cs_free); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int atmel_spi_setup(struct spi_device *spi) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct atmel_spi *as; 12018c2ecf20Sopenharmony_ci struct atmel_spi_device *asd; 12028c2ecf20Sopenharmony_ci u32 csr; 12038c2ecf20Sopenharmony_ci unsigned int bits = spi->bits_per_word; 12048c2ecf20Sopenharmony_ci int chip_select; 12058c2ecf20Sopenharmony_ci int word_delay_csr; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci as = spi_master_get_devdata(spi->master); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci /* see notes above re chipselect */ 12108c2ecf20Sopenharmony_ci if (!spi->cs_gpiod && (spi->mode & SPI_CS_HIGH)) { 12118c2ecf20Sopenharmony_ci dev_warn(&spi->dev, "setup: non GPIO CS can't be active-high\n"); 12128c2ecf20Sopenharmony_ci return -EINVAL; 12138c2ecf20Sopenharmony_ci } 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci /* Setup() is called during spi_register_controller(aka 12168c2ecf20Sopenharmony_ci * spi_register_master) but after all membmers of the cs_gpiod 12178c2ecf20Sopenharmony_ci * array have been filled, so we can looked for which native 12188c2ecf20Sopenharmony_ci * CS will be free for using with GPIO 12198c2ecf20Sopenharmony_ci */ 12208c2ecf20Sopenharmony_ci initialize_native_cs_for_gpio(as); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci if (spi->cs_gpiod && as->native_cs_free) { 12238c2ecf20Sopenharmony_ci dev_err(&spi->dev, 12248c2ecf20Sopenharmony_ci "No native CS available to support this GPIO CS\n"); 12258c2ecf20Sopenharmony_ci return -EBUSY; 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci if (spi->cs_gpiod) 12298c2ecf20Sopenharmony_ci chip_select = as->native_cs_for_gpio; 12308c2ecf20Sopenharmony_ci else 12318c2ecf20Sopenharmony_ci chip_select = spi->chip_select; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci csr = SPI_BF(BITS, bits - 8); 12348c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPOL) 12358c2ecf20Sopenharmony_ci csr |= SPI_BIT(CPOL); 12368c2ecf20Sopenharmony_ci if (!(spi->mode & SPI_CPHA)) 12378c2ecf20Sopenharmony_ci csr |= SPI_BIT(NCPHA); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci if (!spi->cs_gpiod) 12408c2ecf20Sopenharmony_ci csr |= SPI_BIT(CSAAT); 12418c2ecf20Sopenharmony_ci csr |= SPI_BF(DLYBS, 0); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci word_delay_csr = atmel_word_delay_csr(spi, as); 12448c2ecf20Sopenharmony_ci if (word_delay_csr < 0) 12458c2ecf20Sopenharmony_ci return word_delay_csr; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* DLYBCT adds delays between words. This is useful for slow devices 12488c2ecf20Sopenharmony_ci * that need a bit of time to setup the next transfer. 12498c2ecf20Sopenharmony_ci */ 12508c2ecf20Sopenharmony_ci csr |= SPI_BF(DLYBCT, word_delay_csr); 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci asd = spi->controller_state; 12538c2ecf20Sopenharmony_ci if (!asd) { 12548c2ecf20Sopenharmony_ci asd = kzalloc(sizeof(struct atmel_spi_device), GFP_KERNEL); 12558c2ecf20Sopenharmony_ci if (!asd) 12568c2ecf20Sopenharmony_ci return -ENOMEM; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci spi->controller_state = asd; 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci asd->csr = csr; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, 12648c2ecf20Sopenharmony_ci "setup: bpw %u mode 0x%x -> csr%d %08x\n", 12658c2ecf20Sopenharmony_ci bits, spi->mode, spi->chip_select, csr); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci if (!atmel_spi_is_v2(as)) 12688c2ecf20Sopenharmony_ci spi_writel(as, CSR0 + 4 * chip_select, csr); 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci return 0; 12718c2ecf20Sopenharmony_ci} 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_cistatic void atmel_spi_set_cs(struct spi_device *spi, bool enable) 12748c2ecf20Sopenharmony_ci{ 12758c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(spi->master); 12768c2ecf20Sopenharmony_ci /* the core doesn't really pass us enable/disable, but CS HIGH vs CS LOW 12778c2ecf20Sopenharmony_ci * since we already have routines for activate/deactivate translate 12788c2ecf20Sopenharmony_ci * high/low to active/inactive 12798c2ecf20Sopenharmony_ci */ 12808c2ecf20Sopenharmony_ci enable = (!!(spi->mode & SPI_CS_HIGH) == enable); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci if (enable) { 12838c2ecf20Sopenharmony_ci cs_activate(as, spi); 12848c2ecf20Sopenharmony_ci } else { 12858c2ecf20Sopenharmony_ci cs_deactivate(as, spi); 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_cistatic int atmel_spi_one_transfer(struct spi_master *master, 12918c2ecf20Sopenharmony_ci struct spi_device *spi, 12928c2ecf20Sopenharmony_ci struct spi_transfer *xfer) 12938c2ecf20Sopenharmony_ci{ 12948c2ecf20Sopenharmony_ci struct atmel_spi *as; 12958c2ecf20Sopenharmony_ci u8 bits; 12968c2ecf20Sopenharmony_ci u32 len; 12978c2ecf20Sopenharmony_ci struct atmel_spi_device *asd; 12988c2ecf20Sopenharmony_ci int timeout; 12998c2ecf20Sopenharmony_ci int ret; 13008c2ecf20Sopenharmony_ci unsigned long dma_timeout; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci as = spi_master_get_devdata(master); 13038c2ecf20Sopenharmony_ci /* This lock was orignally taken in atmel_spi_trasfer_one_message */ 13048c2ecf20Sopenharmony_ci atmel_spi_lock(as); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci asd = spi->controller_state; 13078c2ecf20Sopenharmony_ci bits = (asd->csr >> 4) & 0xf; 13088c2ecf20Sopenharmony_ci if (bits != xfer->bits_per_word - 8) { 13098c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, 13108c2ecf20Sopenharmony_ci "you can't yet change bits_per_word in transfers\n"); 13118c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci /* 13158c2ecf20Sopenharmony_ci * DMA map early, for performance (empties dcache ASAP) and 13168c2ecf20Sopenharmony_ci * better fault reporting. 13178c2ecf20Sopenharmony_ci */ 13188c2ecf20Sopenharmony_ci if ((!master->cur_msg->is_dma_mapped) 13198c2ecf20Sopenharmony_ci && as->use_pdc) { 13208c2ecf20Sopenharmony_ci if (atmel_spi_dma_map_xfer(as, xfer) < 0) 13218c2ecf20Sopenharmony_ci return -ENOMEM; 13228c2ecf20Sopenharmony_ci } 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci atmel_spi_set_xfer_speed(as, spi, xfer); 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci as->done_status = 0; 13278c2ecf20Sopenharmony_ci as->current_transfer = xfer; 13288c2ecf20Sopenharmony_ci as->current_remaining_bytes = xfer->len; 13298c2ecf20Sopenharmony_ci while (as->current_remaining_bytes) { 13308c2ecf20Sopenharmony_ci reinit_completion(&as->xfer_completion); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci if (as->use_pdc) { 13338c2ecf20Sopenharmony_ci atmel_spi_pdc_next_xfer(master, xfer); 13348c2ecf20Sopenharmony_ci } else if (atmel_spi_use_dma(as, xfer)) { 13358c2ecf20Sopenharmony_ci len = as->current_remaining_bytes; 13368c2ecf20Sopenharmony_ci ret = atmel_spi_next_xfer_dma_submit(master, 13378c2ecf20Sopenharmony_ci xfer, &len); 13388c2ecf20Sopenharmony_ci if (ret) { 13398c2ecf20Sopenharmony_ci dev_err(&spi->dev, 13408c2ecf20Sopenharmony_ci "unable to use DMA, fallback to PIO\n"); 13418c2ecf20Sopenharmony_ci as->done_status = ret; 13428c2ecf20Sopenharmony_ci break; 13438c2ecf20Sopenharmony_ci } else { 13448c2ecf20Sopenharmony_ci as->current_remaining_bytes -= len; 13458c2ecf20Sopenharmony_ci if (as->current_remaining_bytes < 0) 13468c2ecf20Sopenharmony_ci as->current_remaining_bytes = 0; 13478c2ecf20Sopenharmony_ci } 13488c2ecf20Sopenharmony_ci } else { 13498c2ecf20Sopenharmony_ci atmel_spi_next_xfer_pio(master, xfer); 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* interrupts are disabled, so free the lock for schedule */ 13538c2ecf20Sopenharmony_ci atmel_spi_unlock(as); 13548c2ecf20Sopenharmony_ci dma_timeout = wait_for_completion_timeout(&as->xfer_completion, 13558c2ecf20Sopenharmony_ci SPI_DMA_TIMEOUT); 13568c2ecf20Sopenharmony_ci atmel_spi_lock(as); 13578c2ecf20Sopenharmony_ci if (WARN_ON(dma_timeout == 0)) { 13588c2ecf20Sopenharmony_ci dev_err(&spi->dev, "spi transfer timeout\n"); 13598c2ecf20Sopenharmony_ci as->done_status = -EIO; 13608c2ecf20Sopenharmony_ci } 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci if (as->done_status) 13638c2ecf20Sopenharmony_ci break; 13648c2ecf20Sopenharmony_ci } 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (as->done_status) { 13678c2ecf20Sopenharmony_ci if (as->use_pdc) { 13688c2ecf20Sopenharmony_ci dev_warn(master->dev.parent, 13698c2ecf20Sopenharmony_ci "overrun (%u/%u remaining)\n", 13708c2ecf20Sopenharmony_ci spi_readl(as, TCR), spi_readl(as, RCR)); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci /* 13738c2ecf20Sopenharmony_ci * Clean up DMA registers and make sure the data 13748c2ecf20Sopenharmony_ci * registers are empty. 13758c2ecf20Sopenharmony_ci */ 13768c2ecf20Sopenharmony_ci spi_writel(as, RNCR, 0); 13778c2ecf20Sopenharmony_ci spi_writel(as, TNCR, 0); 13788c2ecf20Sopenharmony_ci spi_writel(as, RCR, 0); 13798c2ecf20Sopenharmony_ci spi_writel(as, TCR, 0); 13808c2ecf20Sopenharmony_ci for (timeout = 1000; timeout; timeout--) 13818c2ecf20Sopenharmony_ci if (spi_readl(as, SR) & SPI_BIT(TXEMPTY)) 13828c2ecf20Sopenharmony_ci break; 13838c2ecf20Sopenharmony_ci if (!timeout) 13848c2ecf20Sopenharmony_ci dev_warn(master->dev.parent, 13858c2ecf20Sopenharmony_ci "timeout waiting for TXEMPTY"); 13868c2ecf20Sopenharmony_ci while (spi_readl(as, SR) & SPI_BIT(RDRF)) 13878c2ecf20Sopenharmony_ci spi_readl(as, RDR); 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* Clear any overrun happening while cleaning up */ 13908c2ecf20Sopenharmony_ci spi_readl(as, SR); 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci } else if (atmel_spi_use_dma(as, xfer)) { 13938c2ecf20Sopenharmony_ci atmel_spi_stop_dma(master); 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci if (!master->cur_msg->is_dma_mapped 13988c2ecf20Sopenharmony_ci && as->use_pdc) 13998c2ecf20Sopenharmony_ci atmel_spi_dma_unmap_xfer(master, xfer); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (as->use_pdc) 14028c2ecf20Sopenharmony_ci atmel_spi_disable_pdc_transfer(as); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci atmel_spi_unlock(as); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci return as->done_status; 14078c2ecf20Sopenharmony_ci} 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_cistatic void atmel_spi_cleanup(struct spi_device *spi) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci struct atmel_spi_device *asd = spi->controller_state; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci if (!asd) 14148c2ecf20Sopenharmony_ci return; 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_ci spi->controller_state = NULL; 14178c2ecf20Sopenharmony_ci kfree(asd); 14188c2ecf20Sopenharmony_ci} 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_cistatic inline unsigned int atmel_get_version(struct atmel_spi *as) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci return spi_readl(as, VERSION) & 0x00000fff; 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_cistatic void atmel_get_caps(struct atmel_spi *as) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci unsigned int version; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci version = atmel_get_version(as); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci as->caps.is_spi2 = version > 0x121; 14328c2ecf20Sopenharmony_ci as->caps.has_wdrbt = version >= 0x210; 14338c2ecf20Sopenharmony_ci as->caps.has_dma_support = version >= 0x212; 14348c2ecf20Sopenharmony_ci as->caps.has_pdc_support = version < 0x212; 14358c2ecf20Sopenharmony_ci} 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic void atmel_spi_init(struct atmel_spi *as) 14388c2ecf20Sopenharmony_ci{ 14398c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(SWRST)); 14408c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci /* It is recommended to enable FIFOs first thing after reset */ 14438c2ecf20Sopenharmony_ci if (as->fifo_size) 14448c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(FIFOEN)); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci if (as->caps.has_wdrbt) { 14478c2ecf20Sopenharmony_ci spi_writel(as, MR, SPI_BIT(WDRBT) | SPI_BIT(MODFDIS) 14488c2ecf20Sopenharmony_ci | SPI_BIT(MSTR)); 14498c2ecf20Sopenharmony_ci } else { 14508c2ecf20Sopenharmony_ci spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS)); 14518c2ecf20Sopenharmony_ci } 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci if (as->use_pdc) 14548c2ecf20Sopenharmony_ci spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); 14558c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(SPIEN)); 14568c2ecf20Sopenharmony_ci} 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_cistatic int atmel_spi_probe(struct platform_device *pdev) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci struct resource *regs; 14618c2ecf20Sopenharmony_ci int irq; 14628c2ecf20Sopenharmony_ci struct clk *clk; 14638c2ecf20Sopenharmony_ci int ret; 14648c2ecf20Sopenharmony_ci struct spi_master *master; 14658c2ecf20Sopenharmony_ci struct atmel_spi *as; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci /* Select default pin state */ 14688c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(&pdev->dev); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 14718c2ecf20Sopenharmony_ci if (!regs) 14728c2ecf20Sopenharmony_ci return -ENXIO; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 14758c2ecf20Sopenharmony_ci if (irq < 0) 14768c2ecf20Sopenharmony_ci return irq; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci clk = devm_clk_get(&pdev->dev, "spi_clk"); 14798c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 14808c2ecf20Sopenharmony_ci return PTR_ERR(clk); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci /* setup spi core then atmel-specific driver state */ 14838c2ecf20Sopenharmony_ci master = spi_alloc_master(&pdev->dev, sizeof(*as)); 14848c2ecf20Sopenharmony_ci if (!master) 14858c2ecf20Sopenharmony_ci return -ENOMEM; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci /* the spi->mode bits understood by this driver: */ 14888c2ecf20Sopenharmony_ci master->use_gpio_descriptors = true; 14898c2ecf20Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; 14908c2ecf20Sopenharmony_ci master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 16); 14918c2ecf20Sopenharmony_ci master->dev.of_node = pdev->dev.of_node; 14928c2ecf20Sopenharmony_ci master->bus_num = pdev->id; 14938c2ecf20Sopenharmony_ci master->num_chipselect = 4; 14948c2ecf20Sopenharmony_ci master->setup = atmel_spi_setup; 14958c2ecf20Sopenharmony_ci master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX | 14968c2ecf20Sopenharmony_ci SPI_MASTER_GPIO_SS); 14978c2ecf20Sopenharmony_ci master->transfer_one = atmel_spi_one_transfer; 14988c2ecf20Sopenharmony_ci master->set_cs = atmel_spi_set_cs; 14998c2ecf20Sopenharmony_ci master->cleanup = atmel_spi_cleanup; 15008c2ecf20Sopenharmony_ci master->auto_runtime_pm = true; 15018c2ecf20Sopenharmony_ci master->max_dma_len = SPI_MAX_DMA_XFER; 15028c2ecf20Sopenharmony_ci master->can_dma = atmel_spi_can_dma; 15038c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, master); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci as = spi_master_get_devdata(master); 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci spin_lock_init(&as->lock); 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci as->pdev = pdev; 15108c2ecf20Sopenharmony_ci as->regs = devm_ioremap_resource(&pdev->dev, regs); 15118c2ecf20Sopenharmony_ci if (IS_ERR(as->regs)) { 15128c2ecf20Sopenharmony_ci ret = PTR_ERR(as->regs); 15138c2ecf20Sopenharmony_ci goto out_unmap_regs; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci as->phybase = regs->start; 15168c2ecf20Sopenharmony_ci as->irq = irq; 15178c2ecf20Sopenharmony_ci as->clk = clk; 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_ci init_completion(&as->xfer_completion); 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci atmel_get_caps(as); 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci as->use_dma = false; 15248c2ecf20Sopenharmony_ci as->use_pdc = false; 15258c2ecf20Sopenharmony_ci if (as->caps.has_dma_support) { 15268c2ecf20Sopenharmony_ci ret = atmel_spi_configure_dma(master, as); 15278c2ecf20Sopenharmony_ci if (ret == 0) { 15288c2ecf20Sopenharmony_ci as->use_dma = true; 15298c2ecf20Sopenharmony_ci } else if (ret == -EPROBE_DEFER) { 15308c2ecf20Sopenharmony_ci goto out_unmap_regs; 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci } else if (as->caps.has_pdc_support) { 15338c2ecf20Sopenharmony_ci as->use_pdc = true; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { 15378c2ecf20Sopenharmony_ci as->addr_rx_bbuf = dma_alloc_coherent(&pdev->dev, 15388c2ecf20Sopenharmony_ci SPI_MAX_DMA_XFER, 15398c2ecf20Sopenharmony_ci &as->dma_addr_rx_bbuf, 15408c2ecf20Sopenharmony_ci GFP_KERNEL | GFP_DMA); 15418c2ecf20Sopenharmony_ci if (!as->addr_rx_bbuf) { 15428c2ecf20Sopenharmony_ci as->use_dma = false; 15438c2ecf20Sopenharmony_ci } else { 15448c2ecf20Sopenharmony_ci as->addr_tx_bbuf = dma_alloc_coherent(&pdev->dev, 15458c2ecf20Sopenharmony_ci SPI_MAX_DMA_XFER, 15468c2ecf20Sopenharmony_ci &as->dma_addr_tx_bbuf, 15478c2ecf20Sopenharmony_ci GFP_KERNEL | GFP_DMA); 15488c2ecf20Sopenharmony_ci if (!as->addr_tx_bbuf) { 15498c2ecf20Sopenharmony_ci as->use_dma = false; 15508c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER, 15518c2ecf20Sopenharmony_ci as->addr_rx_bbuf, 15528c2ecf20Sopenharmony_ci as->dma_addr_rx_bbuf); 15538c2ecf20Sopenharmony_ci } 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci if (!as->use_dma) 15568c2ecf20Sopenharmony_ci dev_info(master->dev.parent, 15578c2ecf20Sopenharmony_ci " can not allocate dma coherent memory\n"); 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci if (as->caps.has_dma_support && !as->use_dma) 15618c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Atmel SPI Controller using PIO only\n"); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (as->use_pdc) { 15648c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pdc_interrupt, 15658c2ecf20Sopenharmony_ci 0, dev_name(&pdev->dev), master); 15668c2ecf20Sopenharmony_ci } else { 15678c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, atmel_spi_pio_interrupt, 15688c2ecf20Sopenharmony_ci 0, dev_name(&pdev->dev), master); 15698c2ecf20Sopenharmony_ci } 15708c2ecf20Sopenharmony_ci if (ret) 15718c2ecf20Sopenharmony_ci goto out_unmap_regs; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci /* Initialize the hardware */ 15748c2ecf20Sopenharmony_ci ret = clk_prepare_enable(clk); 15758c2ecf20Sopenharmony_ci if (ret) 15768c2ecf20Sopenharmony_ci goto out_free_irq; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci as->spi_clk = clk_get_rate(clk); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci as->fifo_size = 0; 15818c2ecf20Sopenharmony_ci if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", 15828c2ecf20Sopenharmony_ci &as->fifo_size)) { 15838c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size); 15848c2ecf20Sopenharmony_ci } 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci atmel_spi_init(as); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT); 15898c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(&pdev->dev); 15908c2ecf20Sopenharmony_ci pm_runtime_set_active(&pdev->dev); 15918c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci ret = devm_spi_register_master(&pdev->dev, master); 15948c2ecf20Sopenharmony_ci if (ret) 15958c2ecf20Sopenharmony_ci goto out_free_dma; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci /* go! */ 15988c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Atmel SPI Controller version 0x%x at 0x%08lx (irq %d)\n", 15998c2ecf20Sopenharmony_ci atmel_get_version(as), (unsigned long)regs->start, 16008c2ecf20Sopenharmony_ci irq); 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci return 0; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ciout_free_dma: 16058c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 16068c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&pdev->dev); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci if (as->use_dma) 16098c2ecf20Sopenharmony_ci atmel_spi_release_dma(master); 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(SWRST)); 16128c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ 16138c2ecf20Sopenharmony_ci clk_disable_unprepare(clk); 16148c2ecf20Sopenharmony_ciout_free_irq: 16158c2ecf20Sopenharmony_ciout_unmap_regs: 16168c2ecf20Sopenharmony_ci spi_master_put(master); 16178c2ecf20Sopenharmony_ci return ret; 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cistatic int atmel_spi_remove(struct platform_device *pdev) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci struct spi_master *master = platform_get_drvdata(pdev); 16238c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci /* reset the hardware and block queue progress */ 16288c2ecf20Sopenharmony_ci if (as->use_dma) { 16298c2ecf20Sopenharmony_ci atmel_spi_stop_dma(master); 16308c2ecf20Sopenharmony_ci atmel_spi_release_dma(master); 16318c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_SOC_SAM_V4_V5)) { 16328c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER, 16338c2ecf20Sopenharmony_ci as->addr_tx_bbuf, 16348c2ecf20Sopenharmony_ci as->dma_addr_tx_bbuf); 16358c2ecf20Sopenharmony_ci dma_free_coherent(&pdev->dev, SPI_MAX_DMA_XFER, 16368c2ecf20Sopenharmony_ci as->addr_rx_bbuf, 16378c2ecf20Sopenharmony_ci as->dma_addr_rx_bbuf); 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci spin_lock_irq(&as->lock); 16428c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(SWRST)); 16438c2ecf20Sopenharmony_ci spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */ 16448c2ecf20Sopenharmony_ci spi_readl(as, SR); 16458c2ecf20Sopenharmony_ci spin_unlock_irq(&as->lock); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci clk_disable_unprepare(as->clk); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 16508c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci return 0; 16538c2ecf20Sopenharmony_ci} 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 16568c2ecf20Sopenharmony_cistatic int atmel_spi_runtime_suspend(struct device *dev) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 16598c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci clk_disable_unprepare(as->clk); 16628c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci return 0; 16658c2ecf20Sopenharmony_ci} 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_cistatic int atmel_spi_runtime_resume(struct device *dev) 16688c2ecf20Sopenharmony_ci{ 16698c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 16708c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci return clk_prepare_enable(as->clk); 16758c2ecf20Sopenharmony_ci} 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 16788c2ecf20Sopenharmony_cistatic int atmel_spi_suspend(struct device *dev) 16798c2ecf20Sopenharmony_ci{ 16808c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 16818c2ecf20Sopenharmony_ci int ret; 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci /* Stop the queue running */ 16848c2ecf20Sopenharmony_ci ret = spi_master_suspend(master); 16858c2ecf20Sopenharmony_ci if (ret) 16868c2ecf20Sopenharmony_ci return ret; 16878c2ecf20Sopenharmony_ci 16888c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(dev)) 16898c2ecf20Sopenharmony_ci atmel_spi_runtime_suspend(dev); 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci return 0; 16928c2ecf20Sopenharmony_ci} 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_cistatic int atmel_spi_resume(struct device *dev) 16958c2ecf20Sopenharmony_ci{ 16968c2ecf20Sopenharmony_ci struct spi_master *master = dev_get_drvdata(dev); 16978c2ecf20Sopenharmony_ci struct atmel_spi *as = spi_master_get_devdata(master); 16988c2ecf20Sopenharmony_ci int ret; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci ret = clk_prepare_enable(as->clk); 17018c2ecf20Sopenharmony_ci if (ret) 17028c2ecf20Sopenharmony_ci return ret; 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci atmel_spi_init(as); 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci clk_disable_unprepare(as->clk); 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci if (!pm_runtime_suspended(dev)) { 17098c2ecf20Sopenharmony_ci ret = atmel_spi_runtime_resume(dev); 17108c2ecf20Sopenharmony_ci if (ret) 17118c2ecf20Sopenharmony_ci return ret; 17128c2ecf20Sopenharmony_ci } 17138c2ecf20Sopenharmony_ci 17148c2ecf20Sopenharmony_ci /* Start the queue running */ 17158c2ecf20Sopenharmony_ci return spi_master_resume(master); 17168c2ecf20Sopenharmony_ci} 17178c2ecf20Sopenharmony_ci#endif 17188c2ecf20Sopenharmony_ci 17198c2ecf20Sopenharmony_cistatic const struct dev_pm_ops atmel_spi_pm_ops = { 17208c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume) 17218c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(atmel_spi_runtime_suspend, 17228c2ecf20Sopenharmony_ci atmel_spi_runtime_resume, NULL) 17238c2ecf20Sopenharmony_ci}; 17248c2ecf20Sopenharmony_ci#define ATMEL_SPI_PM_OPS (&atmel_spi_pm_ops) 17258c2ecf20Sopenharmony_ci#else 17268c2ecf20Sopenharmony_ci#define ATMEL_SPI_PM_OPS NULL 17278c2ecf20Sopenharmony_ci#endif 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_cistatic const struct of_device_id atmel_spi_dt_ids[] = { 17308c2ecf20Sopenharmony_ci { .compatible = "atmel,at91rm9200-spi" }, 17318c2ecf20Sopenharmony_ci { /* sentinel */ } 17328c2ecf20Sopenharmony_ci}; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, atmel_spi_dt_ids); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cistatic struct platform_driver atmel_spi_driver = { 17378c2ecf20Sopenharmony_ci .driver = { 17388c2ecf20Sopenharmony_ci .name = "atmel_spi", 17398c2ecf20Sopenharmony_ci .pm = ATMEL_SPI_PM_OPS, 17408c2ecf20Sopenharmony_ci .of_match_table = atmel_spi_dt_ids, 17418c2ecf20Sopenharmony_ci }, 17428c2ecf20Sopenharmony_ci .probe = atmel_spi_probe, 17438c2ecf20Sopenharmony_ci .remove = atmel_spi_remove, 17448c2ecf20Sopenharmony_ci}; 17458c2ecf20Sopenharmony_cimodule_platform_driver(atmel_spi_driver); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver"); 17488c2ecf20Sopenharmony_ciMODULE_AUTHOR("Haavard Skinnemoen (Atmel)"); 17498c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 17508c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:atmel_spi"); 1751