18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * A driver for the ARM PL022 PrimeCell SSP/SPI bus master. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008-2012 ST-Ericsson AB 68c2ecf20Sopenharmony_ci * Copyright (C) 2006 STMicroelectronics Pvt. Ltd. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Author: Linus Walleij <linus.walleij@stericsson.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Initial version inspired by: 118c2ecf20Sopenharmony_ci * linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c 128c2ecf20Sopenharmony_ci * Initial adoption to PL022 by: 138c2ecf20Sopenharmony_ci * Sachin Verma <sachin.verma@st.com> 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/device.h> 198c2ecf20Sopenharmony_ci#include <linux/ioport.h> 208c2ecf20Sopenharmony_ci#include <linux/errno.h> 218c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 228c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <linux/clk.h> 258c2ecf20Sopenharmony_ci#include <linux/err.h> 268c2ecf20Sopenharmony_ci#include <linux/amba/bus.h> 278c2ecf20Sopenharmony_ci#include <linux/amba/pl022.h> 288c2ecf20Sopenharmony_ci#include <linux/io.h> 298c2ecf20Sopenharmony_ci#include <linux/slab.h> 308c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 318c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 328c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 338c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 348c2ecf20Sopenharmony_ci#include <linux/gpio.h> 358c2ecf20Sopenharmony_ci#include <linux/of_gpio.h> 368c2ecf20Sopenharmony_ci#include <linux/pinctrl/consumer.h> 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * This macro is used to define some register default values. 408c2ecf20Sopenharmony_ci * reg is masked with mask, the OR:ed with an (again masked) 418c2ecf20Sopenharmony_ci * val shifted sb steps to the left. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci#define SSP_WRITE_BITS(reg, val, mask, sb) \ 448c2ecf20Sopenharmony_ci ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask)))) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * This macro is also used to define some default values. 488c2ecf20Sopenharmony_ci * It will just shift val by sb steps to the left and mask 498c2ecf20Sopenharmony_ci * the result with mask. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci#define GEN_MASK_BITS(val, mask, sb) \ 528c2ecf20Sopenharmony_ci (((val)<<(sb)) & (mask)) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define DRIVE_TX 0 558c2ecf20Sopenharmony_ci#define DO_NOT_DRIVE_TX 1 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define DO_NOT_QUEUE_DMA 0 588c2ecf20Sopenharmony_ci#define QUEUE_DMA 1 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#define RX_TRANSFER 1 618c2ecf20Sopenharmony_ci#define TX_TRANSFER 2 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * Macros to access SSP Registers with their offsets 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci#define SSP_CR0(r) (r + 0x000) 678c2ecf20Sopenharmony_ci#define SSP_CR1(r) (r + 0x004) 688c2ecf20Sopenharmony_ci#define SSP_DR(r) (r + 0x008) 698c2ecf20Sopenharmony_ci#define SSP_SR(r) (r + 0x00C) 708c2ecf20Sopenharmony_ci#define SSP_CPSR(r) (r + 0x010) 718c2ecf20Sopenharmony_ci#define SSP_IMSC(r) (r + 0x014) 728c2ecf20Sopenharmony_ci#define SSP_RIS(r) (r + 0x018) 738c2ecf20Sopenharmony_ci#define SSP_MIS(r) (r + 0x01C) 748c2ecf20Sopenharmony_ci#define SSP_ICR(r) (r + 0x020) 758c2ecf20Sopenharmony_ci#define SSP_DMACR(r) (r + 0x024) 768c2ecf20Sopenharmony_ci#define SSP_CSR(r) (r + 0x030) /* vendor extension */ 778c2ecf20Sopenharmony_ci#define SSP_ITCR(r) (r + 0x080) 788c2ecf20Sopenharmony_ci#define SSP_ITIP(r) (r + 0x084) 798c2ecf20Sopenharmony_ci#define SSP_ITOP(r) (r + 0x088) 808c2ecf20Sopenharmony_ci#define SSP_TDR(r) (r + 0x08C) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define SSP_PID0(r) (r + 0xFE0) 838c2ecf20Sopenharmony_ci#define SSP_PID1(r) (r + 0xFE4) 848c2ecf20Sopenharmony_ci#define SSP_PID2(r) (r + 0xFE8) 858c2ecf20Sopenharmony_ci#define SSP_PID3(r) (r + 0xFEC) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define SSP_CID0(r) (r + 0xFF0) 888c2ecf20Sopenharmony_ci#define SSP_CID1(r) (r + 0xFF4) 898c2ecf20Sopenharmony_ci#define SSP_CID2(r) (r + 0xFF8) 908c2ecf20Sopenharmony_ci#define SSP_CID3(r) (r + 0xFFC) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* 938c2ecf20Sopenharmony_ci * SSP Control Register 0 - SSP_CR0 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_DSS (0x0FUL << 0) 968c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_FRF (0x3UL << 4) 978c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_SPO (0x1UL << 6) 988c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_SPH (0x1UL << 7) 998c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_SCR (0xFFUL << 8) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* 1028c2ecf20Sopenharmony_ci * The ST version of this block moves som bits 1038c2ecf20Sopenharmony_ci * in SSP_CR0 and extends it to 32 bits 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_DSS_ST (0x1FUL << 0) 1068c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_HALFDUP_ST (0x1UL << 5) 1078c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_CSS_ST (0x1FUL << 16) 1088c2ecf20Sopenharmony_ci#define SSP_CR0_MASK_FRF_ST (0x3UL << 21) 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* 1118c2ecf20Sopenharmony_ci * SSP Control Register 0 - SSP_CR1 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_LBM (0x1UL << 0) 1148c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_SSE (0x1UL << 1) 1158c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_MS (0x1UL << 2) 1168c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_SOD (0x1UL << 3) 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * The ST version of this block adds some bits 1208c2ecf20Sopenharmony_ci * in SSP_CR1 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_RENDN_ST (0x1UL << 4) 1238c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_TENDN_ST (0x1UL << 5) 1248c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_MWAIT_ST (0x1UL << 6) 1258c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_RXIFLSEL_ST (0x7UL << 7) 1268c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_TXIFLSEL_ST (0x7UL << 10) 1278c2ecf20Sopenharmony_ci/* This one is only in the PL023 variant */ 1288c2ecf20Sopenharmony_ci#define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * SSP Status Register - SSP_SR 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci#define SSP_SR_MASK_TFE (0x1UL << 0) /* Transmit FIFO empty */ 1348c2ecf20Sopenharmony_ci#define SSP_SR_MASK_TNF (0x1UL << 1) /* Transmit FIFO not full */ 1358c2ecf20Sopenharmony_ci#define SSP_SR_MASK_RNE (0x1UL << 2) /* Receive FIFO not empty */ 1368c2ecf20Sopenharmony_ci#define SSP_SR_MASK_RFF (0x1UL << 3) /* Receive FIFO full */ 1378c2ecf20Sopenharmony_ci#define SSP_SR_MASK_BSY (0x1UL << 4) /* Busy Flag */ 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * SSP Clock Prescale Register - SSP_CPSR 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci#define SSP_CPSR_MASK_CPSDVSR (0xFFUL << 0) 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/* 1458c2ecf20Sopenharmony_ci * SSP Interrupt Mask Set/Clear Register - SSP_IMSC 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci#define SSP_IMSC_MASK_RORIM (0x1UL << 0) /* Receive Overrun Interrupt mask */ 1488c2ecf20Sopenharmony_ci#define SSP_IMSC_MASK_RTIM (0x1UL << 1) /* Receive timeout Interrupt mask */ 1498c2ecf20Sopenharmony_ci#define SSP_IMSC_MASK_RXIM (0x1UL << 2) /* Receive FIFO Interrupt mask */ 1508c2ecf20Sopenharmony_ci#define SSP_IMSC_MASK_TXIM (0x1UL << 3) /* Transmit FIFO Interrupt mask */ 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * SSP Raw Interrupt Status Register - SSP_RIS 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_ci/* Receive Overrun Raw Interrupt status */ 1568c2ecf20Sopenharmony_ci#define SSP_RIS_MASK_RORRIS (0x1UL << 0) 1578c2ecf20Sopenharmony_ci/* Receive Timeout Raw Interrupt status */ 1588c2ecf20Sopenharmony_ci#define SSP_RIS_MASK_RTRIS (0x1UL << 1) 1598c2ecf20Sopenharmony_ci/* Receive FIFO Raw Interrupt status */ 1608c2ecf20Sopenharmony_ci#define SSP_RIS_MASK_RXRIS (0x1UL << 2) 1618c2ecf20Sopenharmony_ci/* Transmit FIFO Raw Interrupt status */ 1628c2ecf20Sopenharmony_ci#define SSP_RIS_MASK_TXRIS (0x1UL << 3) 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* 1658c2ecf20Sopenharmony_ci * SSP Masked Interrupt Status Register - SSP_MIS 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_ci/* Receive Overrun Masked Interrupt status */ 1688c2ecf20Sopenharmony_ci#define SSP_MIS_MASK_RORMIS (0x1UL << 0) 1698c2ecf20Sopenharmony_ci/* Receive Timeout Masked Interrupt status */ 1708c2ecf20Sopenharmony_ci#define SSP_MIS_MASK_RTMIS (0x1UL << 1) 1718c2ecf20Sopenharmony_ci/* Receive FIFO Masked Interrupt status */ 1728c2ecf20Sopenharmony_ci#define SSP_MIS_MASK_RXMIS (0x1UL << 2) 1738c2ecf20Sopenharmony_ci/* Transmit FIFO Masked Interrupt status */ 1748c2ecf20Sopenharmony_ci#define SSP_MIS_MASK_TXMIS (0x1UL << 3) 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * SSP Interrupt Clear Register - SSP_ICR 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci/* Receive Overrun Raw Clear Interrupt bit */ 1808c2ecf20Sopenharmony_ci#define SSP_ICR_MASK_RORIC (0x1UL << 0) 1818c2ecf20Sopenharmony_ci/* Receive Timeout Clear Interrupt bit */ 1828c2ecf20Sopenharmony_ci#define SSP_ICR_MASK_RTIC (0x1UL << 1) 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* 1858c2ecf20Sopenharmony_ci * SSP DMA Control Register - SSP_DMACR 1868c2ecf20Sopenharmony_ci */ 1878c2ecf20Sopenharmony_ci/* Receive DMA Enable bit */ 1888c2ecf20Sopenharmony_ci#define SSP_DMACR_MASK_RXDMAE (0x1UL << 0) 1898c2ecf20Sopenharmony_ci/* Transmit DMA Enable bit */ 1908c2ecf20Sopenharmony_ci#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1) 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * SSP Chip Select Control Register - SSP_CSR 1948c2ecf20Sopenharmony_ci * (vendor extension) 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci#define SSP_CSR_CSVALUE_MASK (0x1FUL << 0) 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* 1998c2ecf20Sopenharmony_ci * SSP Integration Test control Register - SSP_ITCR 2008c2ecf20Sopenharmony_ci */ 2018c2ecf20Sopenharmony_ci#define SSP_ITCR_MASK_ITEN (0x1UL << 0) 2028c2ecf20Sopenharmony_ci#define SSP_ITCR_MASK_TESTFIFO (0x1UL << 1) 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* 2058c2ecf20Sopenharmony_ci * SSP Integration Test Input Register - SSP_ITIP 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci#define ITIP_MASK_SSPRXD (0x1UL << 0) 2088c2ecf20Sopenharmony_ci#define ITIP_MASK_SSPFSSIN (0x1UL << 1) 2098c2ecf20Sopenharmony_ci#define ITIP_MASK_SSPCLKIN (0x1UL << 2) 2108c2ecf20Sopenharmony_ci#define ITIP_MASK_RXDMAC (0x1UL << 3) 2118c2ecf20Sopenharmony_ci#define ITIP_MASK_TXDMAC (0x1UL << 4) 2128c2ecf20Sopenharmony_ci#define ITIP_MASK_SSPTXDIN (0x1UL << 5) 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci/* 2158c2ecf20Sopenharmony_ci * SSP Integration Test output Register - SSP_ITOP 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci#define ITOP_MASK_SSPTXD (0x1UL << 0) 2188c2ecf20Sopenharmony_ci#define ITOP_MASK_SSPFSSOUT (0x1UL << 1) 2198c2ecf20Sopenharmony_ci#define ITOP_MASK_SSPCLKOUT (0x1UL << 2) 2208c2ecf20Sopenharmony_ci#define ITOP_MASK_SSPOEn (0x1UL << 3) 2218c2ecf20Sopenharmony_ci#define ITOP_MASK_SSPCTLOEn (0x1UL << 4) 2228c2ecf20Sopenharmony_ci#define ITOP_MASK_RORINTR (0x1UL << 5) 2238c2ecf20Sopenharmony_ci#define ITOP_MASK_RTINTR (0x1UL << 6) 2248c2ecf20Sopenharmony_ci#define ITOP_MASK_RXINTR (0x1UL << 7) 2258c2ecf20Sopenharmony_ci#define ITOP_MASK_TXINTR (0x1UL << 8) 2268c2ecf20Sopenharmony_ci#define ITOP_MASK_INTR (0x1UL << 9) 2278c2ecf20Sopenharmony_ci#define ITOP_MASK_RXDMABREQ (0x1UL << 10) 2288c2ecf20Sopenharmony_ci#define ITOP_MASK_RXDMASREQ (0x1UL << 11) 2298c2ecf20Sopenharmony_ci#define ITOP_MASK_TXDMABREQ (0x1UL << 12) 2308c2ecf20Sopenharmony_ci#define ITOP_MASK_TXDMASREQ (0x1UL << 13) 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/* 2338c2ecf20Sopenharmony_ci * SSP Test Data Register - SSP_TDR 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci#define TDR_MASK_TESTDATA (0xFFFFFFFF) 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/* 2388c2ecf20Sopenharmony_ci * Message State 2398c2ecf20Sopenharmony_ci * we use the spi_message.state (void *) pointer to 2408c2ecf20Sopenharmony_ci * hold a single state value, that's why all this 2418c2ecf20Sopenharmony_ci * (void *) casting is done here. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci#define STATE_START ((void *) 0) 2448c2ecf20Sopenharmony_ci#define STATE_RUNNING ((void *) 1) 2458c2ecf20Sopenharmony_ci#define STATE_DONE ((void *) 2) 2468c2ecf20Sopenharmony_ci#define STATE_ERROR ((void *) -1) 2478c2ecf20Sopenharmony_ci#define STATE_TIMEOUT ((void *) -2) 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* 2508c2ecf20Sopenharmony_ci * SSP State - Whether Enabled or Disabled 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci#define SSP_DISABLED (0) 2538c2ecf20Sopenharmony_ci#define SSP_ENABLED (1) 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci/* 2568c2ecf20Sopenharmony_ci * SSP DMA State - Whether DMA Enabled or Disabled 2578c2ecf20Sopenharmony_ci */ 2588c2ecf20Sopenharmony_ci#define SSP_DMA_DISABLED (0) 2598c2ecf20Sopenharmony_ci#define SSP_DMA_ENABLED (1) 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci/* 2628c2ecf20Sopenharmony_ci * SSP Clock Defaults 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci#define SSP_DEFAULT_CLKRATE 0x2 2658c2ecf20Sopenharmony_ci#define SSP_DEFAULT_PRESCALE 0x40 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* 2688c2ecf20Sopenharmony_ci * SSP Clock Parameter ranges 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci#define CPSDVR_MIN 0x02 2718c2ecf20Sopenharmony_ci#define CPSDVR_MAX 0xFE 2728c2ecf20Sopenharmony_ci#define SCR_MIN 0x00 2738c2ecf20Sopenharmony_ci#define SCR_MAX 0xFF 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci/* 2768c2ecf20Sopenharmony_ci * SSP Interrupt related Macros 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_IMSC 0x0UL 2798c2ecf20Sopenharmony_ci#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC 2808c2ecf20Sopenharmony_ci#define ENABLE_ALL_INTERRUPTS ( \ 2818c2ecf20Sopenharmony_ci SSP_IMSC_MASK_RORIM | \ 2828c2ecf20Sopenharmony_ci SSP_IMSC_MASK_RTIM | \ 2838c2ecf20Sopenharmony_ci SSP_IMSC_MASK_RXIM | \ 2848c2ecf20Sopenharmony_ci SSP_IMSC_MASK_TXIM \ 2858c2ecf20Sopenharmony_ci) 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci#define CLEAR_ALL_INTERRUPTS 0x3 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci#define SPI_POLLING_TIMEOUT 1000 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/* 2928c2ecf20Sopenharmony_ci * The type of reading going on on this chip 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_cienum ssp_reading { 2958c2ecf20Sopenharmony_ci READING_NULL, 2968c2ecf20Sopenharmony_ci READING_U8, 2978c2ecf20Sopenharmony_ci READING_U16, 2988c2ecf20Sopenharmony_ci READING_U32 2998c2ecf20Sopenharmony_ci}; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* 3028c2ecf20Sopenharmony_ci * The type of writing going on on this chip 3038c2ecf20Sopenharmony_ci */ 3048c2ecf20Sopenharmony_cienum ssp_writing { 3058c2ecf20Sopenharmony_ci WRITING_NULL, 3068c2ecf20Sopenharmony_ci WRITING_U8, 3078c2ecf20Sopenharmony_ci WRITING_U16, 3088c2ecf20Sopenharmony_ci WRITING_U32 3098c2ecf20Sopenharmony_ci}; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/** 3128c2ecf20Sopenharmony_ci * struct vendor_data - vendor-specific config parameters 3138c2ecf20Sopenharmony_ci * for PL022 derivates 3148c2ecf20Sopenharmony_ci * @fifodepth: depth of FIFOs (both) 3158c2ecf20Sopenharmony_ci * @max_bpw: maximum number of bits per word 3168c2ecf20Sopenharmony_ci * @unidir: supports unidirection transfers 3178c2ecf20Sopenharmony_ci * @extended_cr: 32 bit wide control register 0 with extra 3188c2ecf20Sopenharmony_ci * features and extra features in CR1 as found in the ST variants 3198c2ecf20Sopenharmony_ci * @pl023: supports a subset of the ST extensions called "PL023" 3208c2ecf20Sopenharmony_ci * @loopback: supports loopback mode 3218c2ecf20Sopenharmony_ci * @internal_cs_ctrl: supports chip select control register 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_cistruct vendor_data { 3248c2ecf20Sopenharmony_ci int fifodepth; 3258c2ecf20Sopenharmony_ci int max_bpw; 3268c2ecf20Sopenharmony_ci bool unidir; 3278c2ecf20Sopenharmony_ci bool extended_cr; 3288c2ecf20Sopenharmony_ci bool pl023; 3298c2ecf20Sopenharmony_ci bool loopback; 3308c2ecf20Sopenharmony_ci bool internal_cs_ctrl; 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/** 3348c2ecf20Sopenharmony_ci * struct pl022 - This is the private SSP driver data structure 3358c2ecf20Sopenharmony_ci * @adev: AMBA device model hookup 3368c2ecf20Sopenharmony_ci * @vendor: vendor data for the IP block 3378c2ecf20Sopenharmony_ci * @phybase: the physical memory where the SSP device resides 3388c2ecf20Sopenharmony_ci * @virtbase: the virtual memory where the SSP is mapped 3398c2ecf20Sopenharmony_ci * @clk: outgoing clock "SPICLK" for the SPI bus 3408c2ecf20Sopenharmony_ci * @master: SPI framework hookup 3418c2ecf20Sopenharmony_ci * @master_info: controller-specific data from machine setup 3428c2ecf20Sopenharmony_ci * @pump_transfers: Tasklet used in Interrupt Transfer mode 3438c2ecf20Sopenharmony_ci * @cur_msg: Pointer to current spi_message being processed 3448c2ecf20Sopenharmony_ci * @cur_transfer: Pointer to current spi_transfer 3458c2ecf20Sopenharmony_ci * @cur_chip: pointer to current clients chip(assigned from controller_state) 3468c2ecf20Sopenharmony_ci * @next_msg_cs_active: the next message in the queue has been examined 3478c2ecf20Sopenharmony_ci * and it was found that it uses the same chip select as the previous 3488c2ecf20Sopenharmony_ci * message, so we left it active after the previous transfer, and it's 3498c2ecf20Sopenharmony_ci * active already. 3508c2ecf20Sopenharmony_ci * @tx: current position in TX buffer to be read 3518c2ecf20Sopenharmony_ci * @tx_end: end position in TX buffer to be read 3528c2ecf20Sopenharmony_ci * @rx: current position in RX buffer to be written 3538c2ecf20Sopenharmony_ci * @rx_end: end position in RX buffer to be written 3548c2ecf20Sopenharmony_ci * @read: the type of read currently going on 3558c2ecf20Sopenharmony_ci * @write: the type of write currently going on 3568c2ecf20Sopenharmony_ci * @exp_fifo_level: expected FIFO level 3578c2ecf20Sopenharmony_ci * @rx_lev_trig: receive FIFO watermark level which triggers IRQ 3588c2ecf20Sopenharmony_ci * @tx_lev_trig: transmit FIFO watermark level which triggers IRQ 3598c2ecf20Sopenharmony_ci * @dma_rx_channel: optional channel for RX DMA 3608c2ecf20Sopenharmony_ci * @dma_tx_channel: optional channel for TX DMA 3618c2ecf20Sopenharmony_ci * @sgt_rx: scattertable for the RX transfer 3628c2ecf20Sopenharmony_ci * @sgt_tx: scattertable for the TX transfer 3638c2ecf20Sopenharmony_ci * @dummypage: a dummy page used for driving data on the bus with DMA 3648c2ecf20Sopenharmony_ci * @dma_running: indicates whether DMA is in operation 3658c2ecf20Sopenharmony_ci * @cur_cs: current chip select (gpio) 3668c2ecf20Sopenharmony_ci * @chipselects: list of chipselects (gpios) 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_cistruct pl022 { 3698c2ecf20Sopenharmony_ci struct amba_device *adev; 3708c2ecf20Sopenharmony_ci struct vendor_data *vendor; 3718c2ecf20Sopenharmony_ci resource_size_t phybase; 3728c2ecf20Sopenharmony_ci void __iomem *virtbase; 3738c2ecf20Sopenharmony_ci struct clk *clk; 3748c2ecf20Sopenharmony_ci struct spi_master *master; 3758c2ecf20Sopenharmony_ci struct pl022_ssp_controller *master_info; 3768c2ecf20Sopenharmony_ci /* Message per-transfer pump */ 3778c2ecf20Sopenharmony_ci struct tasklet_struct pump_transfers; 3788c2ecf20Sopenharmony_ci struct spi_message *cur_msg; 3798c2ecf20Sopenharmony_ci struct spi_transfer *cur_transfer; 3808c2ecf20Sopenharmony_ci struct chip_data *cur_chip; 3818c2ecf20Sopenharmony_ci bool next_msg_cs_active; 3828c2ecf20Sopenharmony_ci void *tx; 3838c2ecf20Sopenharmony_ci void *tx_end; 3848c2ecf20Sopenharmony_ci void *rx; 3858c2ecf20Sopenharmony_ci void *rx_end; 3868c2ecf20Sopenharmony_ci enum ssp_reading read; 3878c2ecf20Sopenharmony_ci enum ssp_writing write; 3888c2ecf20Sopenharmony_ci u32 exp_fifo_level; 3898c2ecf20Sopenharmony_ci enum ssp_rx_level_trig rx_lev_trig; 3908c2ecf20Sopenharmony_ci enum ssp_tx_level_trig tx_lev_trig; 3918c2ecf20Sopenharmony_ci /* DMA settings */ 3928c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_ENGINE 3938c2ecf20Sopenharmony_ci struct dma_chan *dma_rx_channel; 3948c2ecf20Sopenharmony_ci struct dma_chan *dma_tx_channel; 3958c2ecf20Sopenharmony_ci struct sg_table sgt_rx; 3968c2ecf20Sopenharmony_ci struct sg_table sgt_tx; 3978c2ecf20Sopenharmony_ci char *dummypage; 3988c2ecf20Sopenharmony_ci bool dma_running; 3998c2ecf20Sopenharmony_ci#endif 4008c2ecf20Sopenharmony_ci int cur_cs; 4018c2ecf20Sopenharmony_ci int *chipselects; 4028c2ecf20Sopenharmony_ci}; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/** 4058c2ecf20Sopenharmony_ci * struct chip_data - To maintain runtime state of SSP for each client chip 4068c2ecf20Sopenharmony_ci * @cr0: Value of control register CR0 of SSP - on later ST variants this 4078c2ecf20Sopenharmony_ci * register is 32 bits wide rather than just 16 4088c2ecf20Sopenharmony_ci * @cr1: Value of control register CR1 of SSP 4098c2ecf20Sopenharmony_ci * @dmacr: Value of DMA control Register of SSP 4108c2ecf20Sopenharmony_ci * @cpsr: Value of Clock prescale register 4118c2ecf20Sopenharmony_ci * @n_bytes: how many bytes(power of 2) reqd for a given data width of client 4128c2ecf20Sopenharmony_ci * @enable_dma: Whether to enable DMA or not 4138c2ecf20Sopenharmony_ci * @read: function ptr to be used to read when doing xfer for this chip 4148c2ecf20Sopenharmony_ci * @write: function ptr to be used to write when doing xfer for this chip 4158c2ecf20Sopenharmony_ci * @cs_control: chip select callback provided by chip 4168c2ecf20Sopenharmony_ci * @xfer_type: polling/interrupt/DMA 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Runtime state of the SSP controller, maintained per chip, 4198c2ecf20Sopenharmony_ci * This would be set according to the current message that would be served 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_cistruct chip_data { 4228c2ecf20Sopenharmony_ci u32 cr0; 4238c2ecf20Sopenharmony_ci u16 cr1; 4248c2ecf20Sopenharmony_ci u16 dmacr; 4258c2ecf20Sopenharmony_ci u16 cpsr; 4268c2ecf20Sopenharmony_ci u8 n_bytes; 4278c2ecf20Sopenharmony_ci bool enable_dma; 4288c2ecf20Sopenharmony_ci enum ssp_reading read; 4298c2ecf20Sopenharmony_ci enum ssp_writing write; 4308c2ecf20Sopenharmony_ci void (*cs_control) (u32 command); 4318c2ecf20Sopenharmony_ci int xfer_type; 4328c2ecf20Sopenharmony_ci}; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci/** 4358c2ecf20Sopenharmony_ci * null_cs_control - Dummy chip select function 4368c2ecf20Sopenharmony_ci * @command: select/delect the chip 4378c2ecf20Sopenharmony_ci * 4388c2ecf20Sopenharmony_ci * If no chip select function is provided by client this is used as dummy 4398c2ecf20Sopenharmony_ci * chip select 4408c2ecf20Sopenharmony_ci */ 4418c2ecf20Sopenharmony_cistatic void null_cs_control(u32 command) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci pr_debug("pl022: dummy chip select control, CS=0x%x\n", command); 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/** 4478c2ecf20Sopenharmony_ci * internal_cs_control - Control chip select signals via SSP_CSR. 4488c2ecf20Sopenharmony_ci * @pl022: SSP driver private data structure 4498c2ecf20Sopenharmony_ci * @command: select/delect the chip 4508c2ecf20Sopenharmony_ci * 4518c2ecf20Sopenharmony_ci * Used on controller with internal chip select control via SSP_CSR register 4528c2ecf20Sopenharmony_ci * (vendor extension). Each of the 5 LSB in the register controls one chip 4538c2ecf20Sopenharmony_ci * select signal. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_cistatic void internal_cs_control(struct pl022 *pl022, u32 command) 4568c2ecf20Sopenharmony_ci{ 4578c2ecf20Sopenharmony_ci u32 tmp; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci tmp = readw(SSP_CSR(pl022->virtbase)); 4608c2ecf20Sopenharmony_ci if (command == SSP_CHIP_SELECT) 4618c2ecf20Sopenharmony_ci tmp &= ~BIT(pl022->cur_cs); 4628c2ecf20Sopenharmony_ci else 4638c2ecf20Sopenharmony_ci tmp |= BIT(pl022->cur_cs); 4648c2ecf20Sopenharmony_ci writew(tmp, SSP_CSR(pl022->virtbase)); 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic void pl022_cs_control(struct pl022 *pl022, u32 command) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci if (pl022->vendor->internal_cs_ctrl) 4708c2ecf20Sopenharmony_ci internal_cs_control(pl022, command); 4718c2ecf20Sopenharmony_ci else if (gpio_is_valid(pl022->cur_cs)) 4728c2ecf20Sopenharmony_ci gpio_set_value(pl022->cur_cs, command); 4738c2ecf20Sopenharmony_ci else 4748c2ecf20Sopenharmony_ci pl022->cur_chip->cs_control(command); 4758c2ecf20Sopenharmony_ci} 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci/** 4788c2ecf20Sopenharmony_ci * giveback - current spi_message is over, schedule next message and call 4798c2ecf20Sopenharmony_ci * callback of this message. Assumes that caller already 4808c2ecf20Sopenharmony_ci * set message->status; dma and pio irqs are blocked 4818c2ecf20Sopenharmony_ci * @pl022: SSP driver private data structure 4828c2ecf20Sopenharmony_ci */ 4838c2ecf20Sopenharmony_cistatic void giveback(struct pl022 *pl022) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct spi_transfer *last_transfer; 4868c2ecf20Sopenharmony_ci pl022->next_msg_cs_active = false; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci last_transfer = list_last_entry(&pl022->cur_msg->transfers, 4898c2ecf20Sopenharmony_ci struct spi_transfer, transfer_list); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci /* Delay if requested before any change in chip select */ 4928c2ecf20Sopenharmony_ci /* 4938c2ecf20Sopenharmony_ci * FIXME: This runs in interrupt context. 4948c2ecf20Sopenharmony_ci * Is this really smart? 4958c2ecf20Sopenharmony_ci */ 4968c2ecf20Sopenharmony_ci spi_transfer_delay_exec(last_transfer); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (!last_transfer->cs_change) { 4998c2ecf20Sopenharmony_ci struct spi_message *next_msg; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci /* 5028c2ecf20Sopenharmony_ci * cs_change was not set. We can keep the chip select 5038c2ecf20Sopenharmony_ci * enabled if there is message in the queue and it is 5048c2ecf20Sopenharmony_ci * for the same spi device. 5058c2ecf20Sopenharmony_ci * 5068c2ecf20Sopenharmony_ci * We cannot postpone this until pump_messages, because 5078c2ecf20Sopenharmony_ci * after calling msg->complete (below) the driver that 5088c2ecf20Sopenharmony_ci * sent the current message could be unloaded, which 5098c2ecf20Sopenharmony_ci * could invalidate the cs_control() callback... 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_ci /* get a pointer to the next message, if any */ 5128c2ecf20Sopenharmony_ci next_msg = spi_get_next_queued_message(pl022->master); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* 5158c2ecf20Sopenharmony_ci * see if the next and current messages point 5168c2ecf20Sopenharmony_ci * to the same spi device. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_ci if (next_msg && next_msg->spi != pl022->cur_msg->spi) 5198c2ecf20Sopenharmony_ci next_msg = NULL; 5208c2ecf20Sopenharmony_ci if (!next_msg || pl022->cur_msg->state == STATE_ERROR) 5218c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 5228c2ecf20Sopenharmony_ci else 5238c2ecf20Sopenharmony_ci pl022->next_msg_cs_active = true; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci pl022->cur_msg = NULL; 5288c2ecf20Sopenharmony_ci pl022->cur_transfer = NULL; 5298c2ecf20Sopenharmony_ci pl022->cur_chip = NULL; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* disable the SPI/SSP operation */ 5328c2ecf20Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & 5338c2ecf20Sopenharmony_ci (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci spi_finalize_current_message(pl022->master); 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci/** 5398c2ecf20Sopenharmony_ci * flush - flush the FIFO to reach a clean state 5408c2ecf20Sopenharmony_ci * @pl022: SSP driver private data structure 5418c2ecf20Sopenharmony_ci */ 5428c2ecf20Sopenharmony_cistatic int flush(struct pl022 *pl022) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci unsigned long limit = loops_per_jiffy << 1; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "flush\n"); 5478c2ecf20Sopenharmony_ci do { 5488c2ecf20Sopenharmony_ci while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) 5498c2ecf20Sopenharmony_ci readw(SSP_DR(pl022->virtbase)); 5508c2ecf20Sopenharmony_ci } while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci pl022->exp_fifo_level = 0; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return limit; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci/** 5588c2ecf20Sopenharmony_ci * restore_state - Load configuration of current chip 5598c2ecf20Sopenharmony_ci * @pl022: SSP driver private data structure 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_cistatic void restore_state(struct pl022 *pl022) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct chip_data *chip = pl022->cur_chip; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (pl022->vendor->extended_cr) 5668c2ecf20Sopenharmony_ci writel(chip->cr0, SSP_CR0(pl022->virtbase)); 5678c2ecf20Sopenharmony_ci else 5688c2ecf20Sopenharmony_ci writew(chip->cr0, SSP_CR0(pl022->virtbase)); 5698c2ecf20Sopenharmony_ci writew(chip->cr1, SSP_CR1(pl022->virtbase)); 5708c2ecf20Sopenharmony_ci writew(chip->dmacr, SSP_DMACR(pl022->virtbase)); 5718c2ecf20Sopenharmony_ci writew(chip->cpsr, SSP_CPSR(pl022->virtbase)); 5728c2ecf20Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); 5738c2ecf20Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/* 5778c2ecf20Sopenharmony_ci * Default SSP Register Values 5788c2ecf20Sopenharmony_ci */ 5798c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_CR0 ( \ 5808c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0) | \ 5818c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 4) | \ 5828c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ 5838c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ 5848c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \ 5858c2ecf20Sopenharmony_ci) 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci/* ST versions have slightly different bit layout */ 5888c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_CR0_ST ( \ 5898c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \ 5908c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP_ST, 5) | \ 5918c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ 5928c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ 5938c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \ 5948c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS_ST, 16) | \ 5958c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF_ST, 21) \ 5968c2ecf20Sopenharmony_ci) 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci/* The PL023 version is slightly different again */ 5998c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_CR0_ST_PL023 ( \ 6008c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \ 6018c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ 6028c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ 6038c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \ 6048c2ecf20Sopenharmony_ci) 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_CR1 ( \ 6078c2ecf20Sopenharmony_ci GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \ 6088c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \ 6098c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \ 6108c2ecf20Sopenharmony_ci GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) \ 6118c2ecf20Sopenharmony_ci) 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci/* ST versions extend this register to use all 16 bits */ 6148c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_CR1_ST ( \ 6158c2ecf20Sopenharmony_ci DEFAULT_SSP_REG_CR1 | \ 6168c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \ 6178c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \ 6188c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT_ST, 6) |\ 6198c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \ 6208c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) \ 6218c2ecf20Sopenharmony_ci) 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* 6248c2ecf20Sopenharmony_ci * The PL023 variant has further differences: no loopback mode, no microwire 6258c2ecf20Sopenharmony_ci * support, and a new clock feedback delay setting. 6268c2ecf20Sopenharmony_ci */ 6278c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_CR1_ST_PL023 ( \ 6288c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \ 6298c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \ 6308c2ecf20Sopenharmony_ci GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \ 6318c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \ 6328c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \ 6338c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \ 6348c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) | \ 6358c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_FEEDBACK_CLK_DELAY_NONE, SSP_CR1_MASK_FBCLKDEL_ST, 13) \ 6368c2ecf20Sopenharmony_ci) 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_CPSR ( \ 6398c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \ 6408c2ecf20Sopenharmony_ci) 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci#define DEFAULT_SSP_REG_DMACR (\ 6438c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0) | \ 6448c2ecf20Sopenharmony_ci GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \ 6458c2ecf20Sopenharmony_ci) 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci/** 6488c2ecf20Sopenharmony_ci * load_ssp_default_config - Load default configuration for SSP 6498c2ecf20Sopenharmony_ci * @pl022: SSP driver private data structure 6508c2ecf20Sopenharmony_ci */ 6518c2ecf20Sopenharmony_cistatic void load_ssp_default_config(struct pl022 *pl022) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci if (pl022->vendor->pl023) { 6548c2ecf20Sopenharmony_ci writel(DEFAULT_SSP_REG_CR0_ST_PL023, SSP_CR0(pl022->virtbase)); 6558c2ecf20Sopenharmony_ci writew(DEFAULT_SSP_REG_CR1_ST_PL023, SSP_CR1(pl022->virtbase)); 6568c2ecf20Sopenharmony_ci } else if (pl022->vendor->extended_cr) { 6578c2ecf20Sopenharmony_ci writel(DEFAULT_SSP_REG_CR0_ST, SSP_CR0(pl022->virtbase)); 6588c2ecf20Sopenharmony_ci writew(DEFAULT_SSP_REG_CR1_ST, SSP_CR1(pl022->virtbase)); 6598c2ecf20Sopenharmony_ci } else { 6608c2ecf20Sopenharmony_ci writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase)); 6618c2ecf20Sopenharmony_ci writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase)); 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase)); 6648c2ecf20Sopenharmony_ci writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase)); 6658c2ecf20Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); 6668c2ecf20Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci/* 6708c2ecf20Sopenharmony_ci * This will write to TX and read from RX according to the parameters 6718c2ecf20Sopenharmony_ci * set in pl022. 6728c2ecf20Sopenharmony_ci */ 6738c2ecf20Sopenharmony_cistatic void readwriter(struct pl022 *pl022) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci /* 6778c2ecf20Sopenharmony_ci * The FIFO depth is different between primecell variants. 6788c2ecf20Sopenharmony_ci * I believe filling in too much in the FIFO might cause 6798c2ecf20Sopenharmony_ci * errons in 8bit wide transfers on ARM variants (just 8 words 6808c2ecf20Sopenharmony_ci * FIFO, means only 8x8 = 64 bits in FIFO) at least. 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * To prevent this issue, the TX FIFO is only filled to the 6838c2ecf20Sopenharmony_ci * unused RX FIFO fill length, regardless of what the TX 6848c2ecf20Sopenharmony_ci * FIFO status flag indicates. 6858c2ecf20Sopenharmony_ci */ 6868c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, 6878c2ecf20Sopenharmony_ci "%s, rx: %p, rxend: %p, tx: %p, txend: %p\n", 6888c2ecf20Sopenharmony_ci __func__, pl022->rx, pl022->rx_end, pl022->tx, pl022->tx_end); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Read as much as you can */ 6918c2ecf20Sopenharmony_ci while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) 6928c2ecf20Sopenharmony_ci && (pl022->rx < pl022->rx_end)) { 6938c2ecf20Sopenharmony_ci switch (pl022->read) { 6948c2ecf20Sopenharmony_ci case READING_NULL: 6958c2ecf20Sopenharmony_ci readw(SSP_DR(pl022->virtbase)); 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci case READING_U8: 6988c2ecf20Sopenharmony_ci *(u8 *) (pl022->rx) = 6998c2ecf20Sopenharmony_ci readw(SSP_DR(pl022->virtbase)) & 0xFFU; 7008c2ecf20Sopenharmony_ci break; 7018c2ecf20Sopenharmony_ci case READING_U16: 7028c2ecf20Sopenharmony_ci *(u16 *) (pl022->rx) = 7038c2ecf20Sopenharmony_ci (u16) readw(SSP_DR(pl022->virtbase)); 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci case READING_U32: 7068c2ecf20Sopenharmony_ci *(u32 *) (pl022->rx) = 7078c2ecf20Sopenharmony_ci readl(SSP_DR(pl022->virtbase)); 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci } 7108c2ecf20Sopenharmony_ci pl022->rx += (pl022->cur_chip->n_bytes); 7118c2ecf20Sopenharmony_ci pl022->exp_fifo_level--; 7128c2ecf20Sopenharmony_ci } 7138c2ecf20Sopenharmony_ci /* 7148c2ecf20Sopenharmony_ci * Write as much as possible up to the RX FIFO size 7158c2ecf20Sopenharmony_ci */ 7168c2ecf20Sopenharmony_ci while ((pl022->exp_fifo_level < pl022->vendor->fifodepth) 7178c2ecf20Sopenharmony_ci && (pl022->tx < pl022->tx_end)) { 7188c2ecf20Sopenharmony_ci switch (pl022->write) { 7198c2ecf20Sopenharmony_ci case WRITING_NULL: 7208c2ecf20Sopenharmony_ci writew(0x0, SSP_DR(pl022->virtbase)); 7218c2ecf20Sopenharmony_ci break; 7228c2ecf20Sopenharmony_ci case WRITING_U8: 7238c2ecf20Sopenharmony_ci writew(*(u8 *) (pl022->tx), SSP_DR(pl022->virtbase)); 7248c2ecf20Sopenharmony_ci break; 7258c2ecf20Sopenharmony_ci case WRITING_U16: 7268c2ecf20Sopenharmony_ci writew((*(u16 *) (pl022->tx)), SSP_DR(pl022->virtbase)); 7278c2ecf20Sopenharmony_ci break; 7288c2ecf20Sopenharmony_ci case WRITING_U32: 7298c2ecf20Sopenharmony_ci writel(*(u32 *) (pl022->tx), SSP_DR(pl022->virtbase)); 7308c2ecf20Sopenharmony_ci break; 7318c2ecf20Sopenharmony_ci } 7328c2ecf20Sopenharmony_ci pl022->tx += (pl022->cur_chip->n_bytes); 7338c2ecf20Sopenharmony_ci pl022->exp_fifo_level++; 7348c2ecf20Sopenharmony_ci /* 7358c2ecf20Sopenharmony_ci * This inner reader takes care of things appearing in the RX 7368c2ecf20Sopenharmony_ci * FIFO as we're transmitting. This will happen a lot since the 7378c2ecf20Sopenharmony_ci * clock starts running when you put things into the TX FIFO, 7388c2ecf20Sopenharmony_ci * and then things are continuously clocked into the RX FIFO. 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_ci while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) 7418c2ecf20Sopenharmony_ci && (pl022->rx < pl022->rx_end)) { 7428c2ecf20Sopenharmony_ci switch (pl022->read) { 7438c2ecf20Sopenharmony_ci case READING_NULL: 7448c2ecf20Sopenharmony_ci readw(SSP_DR(pl022->virtbase)); 7458c2ecf20Sopenharmony_ci break; 7468c2ecf20Sopenharmony_ci case READING_U8: 7478c2ecf20Sopenharmony_ci *(u8 *) (pl022->rx) = 7488c2ecf20Sopenharmony_ci readw(SSP_DR(pl022->virtbase)) & 0xFFU; 7498c2ecf20Sopenharmony_ci break; 7508c2ecf20Sopenharmony_ci case READING_U16: 7518c2ecf20Sopenharmony_ci *(u16 *) (pl022->rx) = 7528c2ecf20Sopenharmony_ci (u16) readw(SSP_DR(pl022->virtbase)); 7538c2ecf20Sopenharmony_ci break; 7548c2ecf20Sopenharmony_ci case READING_U32: 7558c2ecf20Sopenharmony_ci *(u32 *) (pl022->rx) = 7568c2ecf20Sopenharmony_ci readl(SSP_DR(pl022->virtbase)); 7578c2ecf20Sopenharmony_ci break; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci pl022->rx += (pl022->cur_chip->n_bytes); 7608c2ecf20Sopenharmony_ci pl022->exp_fifo_level--; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci } 7638c2ecf20Sopenharmony_ci /* 7648c2ecf20Sopenharmony_ci * When we exit here the TX FIFO should be full and the RX FIFO 7658c2ecf20Sopenharmony_ci * should be empty 7668c2ecf20Sopenharmony_ci */ 7678c2ecf20Sopenharmony_ci} 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci/** 7708c2ecf20Sopenharmony_ci * next_transfer - Move to the Next transfer in the current spi message 7718c2ecf20Sopenharmony_ci * @pl022: SSP driver private data structure 7728c2ecf20Sopenharmony_ci * 7738c2ecf20Sopenharmony_ci * This function moves though the linked list of spi transfers in the 7748c2ecf20Sopenharmony_ci * current spi message and returns with the state of current spi 7758c2ecf20Sopenharmony_ci * message i.e whether its last transfer is done(STATE_DONE) or 7768c2ecf20Sopenharmony_ci * Next transfer is ready(STATE_RUNNING) 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_cistatic void *next_transfer(struct pl022 *pl022) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct spi_message *msg = pl022->cur_msg; 7818c2ecf20Sopenharmony_ci struct spi_transfer *trans = pl022->cur_transfer; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci /* Move to next transfer */ 7848c2ecf20Sopenharmony_ci if (trans->transfer_list.next != &msg->transfers) { 7858c2ecf20Sopenharmony_ci pl022->cur_transfer = 7868c2ecf20Sopenharmony_ci list_entry(trans->transfer_list.next, 7878c2ecf20Sopenharmony_ci struct spi_transfer, transfer_list); 7888c2ecf20Sopenharmony_ci return STATE_RUNNING; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci return STATE_DONE; 7918c2ecf20Sopenharmony_ci} 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci/* 7948c2ecf20Sopenharmony_ci * This DMA functionality is only compiled in if we have 7958c2ecf20Sopenharmony_ci * access to the generic DMA devices/DMA engine. 7968c2ecf20Sopenharmony_ci */ 7978c2ecf20Sopenharmony_ci#ifdef CONFIG_DMA_ENGINE 7988c2ecf20Sopenharmony_cistatic void unmap_free_dma_scatter(struct pl022 *pl022) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci /* Unmap and free the SG tables */ 8018c2ecf20Sopenharmony_ci dma_unmap_sg(pl022->dma_tx_channel->device->dev, pl022->sgt_tx.sgl, 8028c2ecf20Sopenharmony_ci pl022->sgt_tx.nents, DMA_TO_DEVICE); 8038c2ecf20Sopenharmony_ci dma_unmap_sg(pl022->dma_rx_channel->device->dev, pl022->sgt_rx.sgl, 8048c2ecf20Sopenharmony_ci pl022->sgt_rx.nents, DMA_FROM_DEVICE); 8058c2ecf20Sopenharmony_ci sg_free_table(&pl022->sgt_rx); 8068c2ecf20Sopenharmony_ci sg_free_table(&pl022->sgt_tx); 8078c2ecf20Sopenharmony_ci} 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_cistatic void dma_callback(void *data) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct pl022 *pl022 = data; 8128c2ecf20Sopenharmony_ci struct spi_message *msg = pl022->cur_msg; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci BUG_ON(!pl022->sgt_rx.sgl); 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci#ifdef VERBOSE_DEBUG 8178c2ecf20Sopenharmony_ci /* 8188c2ecf20Sopenharmony_ci * Optionally dump out buffers to inspect contents, this is 8198c2ecf20Sopenharmony_ci * good if you want to convince yourself that the loopback 8208c2ecf20Sopenharmony_ci * read/write contents are the same, when adopting to a new 8218c2ecf20Sopenharmony_ci * DMA engine. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ci { 8248c2ecf20Sopenharmony_ci struct scatterlist *sg; 8258c2ecf20Sopenharmony_ci unsigned int i; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci dma_sync_sg_for_cpu(&pl022->adev->dev, 8288c2ecf20Sopenharmony_ci pl022->sgt_rx.sgl, 8298c2ecf20Sopenharmony_ci pl022->sgt_rx.nents, 8308c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci for_each_sg(pl022->sgt_rx.sgl, sg, pl022->sgt_rx.nents, i) { 8338c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "SPI RX SG ENTRY: %d", i); 8348c2ecf20Sopenharmony_ci print_hex_dump(KERN_ERR, "SPI RX: ", 8358c2ecf20Sopenharmony_ci DUMP_PREFIX_OFFSET, 8368c2ecf20Sopenharmony_ci 16, 8378c2ecf20Sopenharmony_ci 1, 8388c2ecf20Sopenharmony_ci sg_virt(sg), 8398c2ecf20Sopenharmony_ci sg_dma_len(sg), 8408c2ecf20Sopenharmony_ci 1); 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci for_each_sg(pl022->sgt_tx.sgl, sg, pl022->sgt_tx.nents, i) { 8438c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "SPI TX SG ENTRY: %d", i); 8448c2ecf20Sopenharmony_ci print_hex_dump(KERN_ERR, "SPI TX: ", 8458c2ecf20Sopenharmony_ci DUMP_PREFIX_OFFSET, 8468c2ecf20Sopenharmony_ci 16, 8478c2ecf20Sopenharmony_ci 1, 8488c2ecf20Sopenharmony_ci sg_virt(sg), 8498c2ecf20Sopenharmony_ci sg_dma_len(sg), 8508c2ecf20Sopenharmony_ci 1); 8518c2ecf20Sopenharmony_ci } 8528c2ecf20Sopenharmony_ci } 8538c2ecf20Sopenharmony_ci#endif 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci unmap_free_dma_scatter(pl022); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Update total bytes transferred */ 8588c2ecf20Sopenharmony_ci msg->actual_length += pl022->cur_transfer->len; 8598c2ecf20Sopenharmony_ci /* Move to next transfer */ 8608c2ecf20Sopenharmony_ci msg->state = next_transfer(pl022); 8618c2ecf20Sopenharmony_ci if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change) 8628c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 8638c2ecf20Sopenharmony_ci tasklet_schedule(&pl022->pump_transfers); 8648c2ecf20Sopenharmony_ci} 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_cistatic void setup_dma_scatter(struct pl022 *pl022, 8678c2ecf20Sopenharmony_ci void *buffer, 8688c2ecf20Sopenharmony_ci unsigned int length, 8698c2ecf20Sopenharmony_ci struct sg_table *sgtab) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci struct scatterlist *sg; 8728c2ecf20Sopenharmony_ci int bytesleft = length; 8738c2ecf20Sopenharmony_ci void *bufp = buffer; 8748c2ecf20Sopenharmony_ci int mapbytes; 8758c2ecf20Sopenharmony_ci int i; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (buffer) { 8788c2ecf20Sopenharmony_ci for_each_sg(sgtab->sgl, sg, sgtab->nents, i) { 8798c2ecf20Sopenharmony_ci /* 8808c2ecf20Sopenharmony_ci * If there are less bytes left than what fits 8818c2ecf20Sopenharmony_ci * in the current page (plus page alignment offset) 8828c2ecf20Sopenharmony_ci * we just feed in this, else we stuff in as much 8838c2ecf20Sopenharmony_ci * as we can. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci if (bytesleft < (PAGE_SIZE - offset_in_page(bufp))) 8868c2ecf20Sopenharmony_ci mapbytes = bytesleft; 8878c2ecf20Sopenharmony_ci else 8888c2ecf20Sopenharmony_ci mapbytes = PAGE_SIZE - offset_in_page(bufp); 8898c2ecf20Sopenharmony_ci sg_set_page(sg, virt_to_page(bufp), 8908c2ecf20Sopenharmony_ci mapbytes, offset_in_page(bufp)); 8918c2ecf20Sopenharmony_ci bufp += mapbytes; 8928c2ecf20Sopenharmony_ci bytesleft -= mapbytes; 8938c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, 8948c2ecf20Sopenharmony_ci "set RX/TX target page @ %p, %d bytes, %d left\n", 8958c2ecf20Sopenharmony_ci bufp, mapbytes, bytesleft); 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci } else { 8988c2ecf20Sopenharmony_ci /* Map the dummy buffer on every page */ 8998c2ecf20Sopenharmony_ci for_each_sg(sgtab->sgl, sg, sgtab->nents, i) { 9008c2ecf20Sopenharmony_ci if (bytesleft < PAGE_SIZE) 9018c2ecf20Sopenharmony_ci mapbytes = bytesleft; 9028c2ecf20Sopenharmony_ci else 9038c2ecf20Sopenharmony_ci mapbytes = PAGE_SIZE; 9048c2ecf20Sopenharmony_ci sg_set_page(sg, virt_to_page(pl022->dummypage), 9058c2ecf20Sopenharmony_ci mapbytes, 0); 9068c2ecf20Sopenharmony_ci bytesleft -= mapbytes; 9078c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, 9088c2ecf20Sopenharmony_ci "set RX/TX to dummy page %d bytes, %d left\n", 9098c2ecf20Sopenharmony_ci mapbytes, bytesleft); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci } 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci BUG_ON(bytesleft); 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci/** 9178c2ecf20Sopenharmony_ci * configure_dma - configures the channels for the next transfer 9188c2ecf20Sopenharmony_ci * @pl022: SSP driver's private data structure 9198c2ecf20Sopenharmony_ci */ 9208c2ecf20Sopenharmony_cistatic int configure_dma(struct pl022 *pl022) 9218c2ecf20Sopenharmony_ci{ 9228c2ecf20Sopenharmony_ci struct dma_slave_config rx_conf = { 9238c2ecf20Sopenharmony_ci .src_addr = SSP_DR(pl022->phybase), 9248c2ecf20Sopenharmony_ci .direction = DMA_DEV_TO_MEM, 9258c2ecf20Sopenharmony_ci .device_fc = false, 9268c2ecf20Sopenharmony_ci }; 9278c2ecf20Sopenharmony_ci struct dma_slave_config tx_conf = { 9288c2ecf20Sopenharmony_ci .dst_addr = SSP_DR(pl022->phybase), 9298c2ecf20Sopenharmony_ci .direction = DMA_MEM_TO_DEV, 9308c2ecf20Sopenharmony_ci .device_fc = false, 9318c2ecf20Sopenharmony_ci }; 9328c2ecf20Sopenharmony_ci unsigned int pages; 9338c2ecf20Sopenharmony_ci int ret; 9348c2ecf20Sopenharmony_ci int rx_sglen, tx_sglen; 9358c2ecf20Sopenharmony_ci struct dma_chan *rxchan = pl022->dma_rx_channel; 9368c2ecf20Sopenharmony_ci struct dma_chan *txchan = pl022->dma_tx_channel; 9378c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc; 9388c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *txdesc; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* Check that the channels are available */ 9418c2ecf20Sopenharmony_ci if (!rxchan || !txchan) 9428c2ecf20Sopenharmony_ci return -ENODEV; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* 9458c2ecf20Sopenharmony_ci * If supplied, the DMA burstsize should equal the FIFO trigger level. 9468c2ecf20Sopenharmony_ci * Notice that the DMA engine uses one-to-one mapping. Since we can 9478c2ecf20Sopenharmony_ci * not trigger on 2 elements this needs explicit mapping rather than 9488c2ecf20Sopenharmony_ci * calculation. 9498c2ecf20Sopenharmony_ci */ 9508c2ecf20Sopenharmony_ci switch (pl022->rx_lev_trig) { 9518c2ecf20Sopenharmony_ci case SSP_RX_1_OR_MORE_ELEM: 9528c2ecf20Sopenharmony_ci rx_conf.src_maxburst = 1; 9538c2ecf20Sopenharmony_ci break; 9548c2ecf20Sopenharmony_ci case SSP_RX_4_OR_MORE_ELEM: 9558c2ecf20Sopenharmony_ci rx_conf.src_maxburst = 4; 9568c2ecf20Sopenharmony_ci break; 9578c2ecf20Sopenharmony_ci case SSP_RX_8_OR_MORE_ELEM: 9588c2ecf20Sopenharmony_ci rx_conf.src_maxburst = 8; 9598c2ecf20Sopenharmony_ci break; 9608c2ecf20Sopenharmony_ci case SSP_RX_16_OR_MORE_ELEM: 9618c2ecf20Sopenharmony_ci rx_conf.src_maxburst = 16; 9628c2ecf20Sopenharmony_ci break; 9638c2ecf20Sopenharmony_ci case SSP_RX_32_OR_MORE_ELEM: 9648c2ecf20Sopenharmony_ci rx_conf.src_maxburst = 32; 9658c2ecf20Sopenharmony_ci break; 9668c2ecf20Sopenharmony_ci default: 9678c2ecf20Sopenharmony_ci rx_conf.src_maxburst = pl022->vendor->fifodepth >> 1; 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci switch (pl022->tx_lev_trig) { 9728c2ecf20Sopenharmony_ci case SSP_TX_1_OR_MORE_EMPTY_LOC: 9738c2ecf20Sopenharmony_ci tx_conf.dst_maxburst = 1; 9748c2ecf20Sopenharmony_ci break; 9758c2ecf20Sopenharmony_ci case SSP_TX_4_OR_MORE_EMPTY_LOC: 9768c2ecf20Sopenharmony_ci tx_conf.dst_maxburst = 4; 9778c2ecf20Sopenharmony_ci break; 9788c2ecf20Sopenharmony_ci case SSP_TX_8_OR_MORE_EMPTY_LOC: 9798c2ecf20Sopenharmony_ci tx_conf.dst_maxburst = 8; 9808c2ecf20Sopenharmony_ci break; 9818c2ecf20Sopenharmony_ci case SSP_TX_16_OR_MORE_EMPTY_LOC: 9828c2ecf20Sopenharmony_ci tx_conf.dst_maxburst = 16; 9838c2ecf20Sopenharmony_ci break; 9848c2ecf20Sopenharmony_ci case SSP_TX_32_OR_MORE_EMPTY_LOC: 9858c2ecf20Sopenharmony_ci tx_conf.dst_maxburst = 32; 9868c2ecf20Sopenharmony_ci break; 9878c2ecf20Sopenharmony_ci default: 9888c2ecf20Sopenharmony_ci tx_conf.dst_maxburst = pl022->vendor->fifodepth >> 1; 9898c2ecf20Sopenharmony_ci break; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci switch (pl022->read) { 9938c2ecf20Sopenharmony_ci case READING_NULL: 9948c2ecf20Sopenharmony_ci /* Use the same as for writing */ 9958c2ecf20Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; 9968c2ecf20Sopenharmony_ci break; 9978c2ecf20Sopenharmony_ci case READING_U8: 9988c2ecf20Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 9998c2ecf20Sopenharmony_ci break; 10008c2ecf20Sopenharmony_ci case READING_U16: 10018c2ecf20Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 10028c2ecf20Sopenharmony_ci break; 10038c2ecf20Sopenharmony_ci case READING_U32: 10048c2ecf20Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 10058c2ecf20Sopenharmony_ci break; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci switch (pl022->write) { 10098c2ecf20Sopenharmony_ci case WRITING_NULL: 10108c2ecf20Sopenharmony_ci /* Use the same as for reading */ 10118c2ecf20Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; 10128c2ecf20Sopenharmony_ci break; 10138c2ecf20Sopenharmony_ci case WRITING_U8: 10148c2ecf20Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci case WRITING_U16: 10178c2ecf20Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 10188c2ecf20Sopenharmony_ci break; 10198c2ecf20Sopenharmony_ci case WRITING_U32: 10208c2ecf20Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 10218c2ecf20Sopenharmony_ci break; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci /* SPI pecularity: we need to read and write the same width */ 10258c2ecf20Sopenharmony_ci if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) 10268c2ecf20Sopenharmony_ci rx_conf.src_addr_width = tx_conf.dst_addr_width; 10278c2ecf20Sopenharmony_ci if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) 10288c2ecf20Sopenharmony_ci tx_conf.dst_addr_width = rx_conf.src_addr_width; 10298c2ecf20Sopenharmony_ci BUG_ON(rx_conf.src_addr_width != tx_conf.dst_addr_width); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci dmaengine_slave_config(rxchan, &rx_conf); 10328c2ecf20Sopenharmony_ci dmaengine_slave_config(txchan, &tx_conf); 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci /* Create sglists for the transfers */ 10358c2ecf20Sopenharmony_ci pages = DIV_ROUND_UP(pl022->cur_transfer->len, PAGE_SIZE); 10368c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_ATOMIC); 10398c2ecf20Sopenharmony_ci if (ret) 10408c2ecf20Sopenharmony_ci goto err_alloc_rx_sg; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_ATOMIC); 10438c2ecf20Sopenharmony_ci if (ret) 10448c2ecf20Sopenharmony_ci goto err_alloc_tx_sg; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* Fill in the scatterlists for the RX+TX buffers */ 10478c2ecf20Sopenharmony_ci setup_dma_scatter(pl022, pl022->rx, 10488c2ecf20Sopenharmony_ci pl022->cur_transfer->len, &pl022->sgt_rx); 10498c2ecf20Sopenharmony_ci setup_dma_scatter(pl022, pl022->tx, 10508c2ecf20Sopenharmony_ci pl022->cur_transfer->len, &pl022->sgt_tx); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* Map DMA buffers */ 10538c2ecf20Sopenharmony_ci rx_sglen = dma_map_sg(rxchan->device->dev, pl022->sgt_rx.sgl, 10548c2ecf20Sopenharmony_ci pl022->sgt_rx.nents, DMA_FROM_DEVICE); 10558c2ecf20Sopenharmony_ci if (!rx_sglen) 10568c2ecf20Sopenharmony_ci goto err_rx_sgmap; 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci tx_sglen = dma_map_sg(txchan->device->dev, pl022->sgt_tx.sgl, 10598c2ecf20Sopenharmony_ci pl022->sgt_tx.nents, DMA_TO_DEVICE); 10608c2ecf20Sopenharmony_ci if (!tx_sglen) 10618c2ecf20Sopenharmony_ci goto err_tx_sgmap; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci /* Send both scatterlists */ 10648c2ecf20Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg(rxchan, 10658c2ecf20Sopenharmony_ci pl022->sgt_rx.sgl, 10668c2ecf20Sopenharmony_ci rx_sglen, 10678c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 10688c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 10698c2ecf20Sopenharmony_ci if (!rxdesc) 10708c2ecf20Sopenharmony_ci goto err_rxdesc; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci txdesc = dmaengine_prep_slave_sg(txchan, 10738c2ecf20Sopenharmony_ci pl022->sgt_tx.sgl, 10748c2ecf20Sopenharmony_ci tx_sglen, 10758c2ecf20Sopenharmony_ci DMA_MEM_TO_DEV, 10768c2ecf20Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 10778c2ecf20Sopenharmony_ci if (!txdesc) 10788c2ecf20Sopenharmony_ci goto err_txdesc; 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci /* Put the callback on the RX transfer only, that should finish last */ 10818c2ecf20Sopenharmony_ci rxdesc->callback = dma_callback; 10828c2ecf20Sopenharmony_ci rxdesc->callback_param = pl022; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* Submit and fire RX and TX with TX last so we're ready to read! */ 10858c2ecf20Sopenharmony_ci dmaengine_submit(rxdesc); 10868c2ecf20Sopenharmony_ci dmaengine_submit(txdesc); 10878c2ecf20Sopenharmony_ci dma_async_issue_pending(rxchan); 10888c2ecf20Sopenharmony_ci dma_async_issue_pending(txchan); 10898c2ecf20Sopenharmony_ci pl022->dma_running = true; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci return 0; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_cierr_txdesc: 10948c2ecf20Sopenharmony_ci dmaengine_terminate_all(txchan); 10958c2ecf20Sopenharmony_cierr_rxdesc: 10968c2ecf20Sopenharmony_ci dmaengine_terminate_all(rxchan); 10978c2ecf20Sopenharmony_ci dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl, 10988c2ecf20Sopenharmony_ci pl022->sgt_tx.nents, DMA_TO_DEVICE); 10998c2ecf20Sopenharmony_cierr_tx_sgmap: 11008c2ecf20Sopenharmony_ci dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl, 11018c2ecf20Sopenharmony_ci pl022->sgt_rx.nents, DMA_FROM_DEVICE); 11028c2ecf20Sopenharmony_cierr_rx_sgmap: 11038c2ecf20Sopenharmony_ci sg_free_table(&pl022->sgt_tx); 11048c2ecf20Sopenharmony_cierr_alloc_tx_sg: 11058c2ecf20Sopenharmony_ci sg_free_table(&pl022->sgt_rx); 11068c2ecf20Sopenharmony_cierr_alloc_rx_sg: 11078c2ecf20Sopenharmony_ci return -ENOMEM; 11088c2ecf20Sopenharmony_ci} 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_cistatic int pl022_dma_probe(struct pl022 *pl022) 11118c2ecf20Sopenharmony_ci{ 11128c2ecf20Sopenharmony_ci dma_cap_mask_t mask; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci /* Try to acquire a generic DMA engine slave channel */ 11158c2ecf20Sopenharmony_ci dma_cap_zero(mask); 11168c2ecf20Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 11178c2ecf20Sopenharmony_ci /* 11188c2ecf20Sopenharmony_ci * We need both RX and TX channels to do DMA, else do none 11198c2ecf20Sopenharmony_ci * of them. 11208c2ecf20Sopenharmony_ci */ 11218c2ecf20Sopenharmony_ci pl022->dma_rx_channel = dma_request_channel(mask, 11228c2ecf20Sopenharmony_ci pl022->master_info->dma_filter, 11238c2ecf20Sopenharmony_ci pl022->master_info->dma_rx_param); 11248c2ecf20Sopenharmony_ci if (!pl022->dma_rx_channel) { 11258c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "no RX DMA channel!\n"); 11268c2ecf20Sopenharmony_ci goto err_no_rxchan; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci pl022->dma_tx_channel = dma_request_channel(mask, 11308c2ecf20Sopenharmony_ci pl022->master_info->dma_filter, 11318c2ecf20Sopenharmony_ci pl022->master_info->dma_tx_param); 11328c2ecf20Sopenharmony_ci if (!pl022->dma_tx_channel) { 11338c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "no TX DMA channel!\n"); 11348c2ecf20Sopenharmony_ci goto err_no_txchan; 11358c2ecf20Sopenharmony_ci } 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); 11388c2ecf20Sopenharmony_ci if (!pl022->dummypage) 11398c2ecf20Sopenharmony_ci goto err_no_dummypage; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s\n", 11428c2ecf20Sopenharmony_ci dma_chan_name(pl022->dma_rx_channel), 11438c2ecf20Sopenharmony_ci dma_chan_name(pl022->dma_tx_channel)); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci return 0; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cierr_no_dummypage: 11488c2ecf20Sopenharmony_ci dma_release_channel(pl022->dma_tx_channel); 11498c2ecf20Sopenharmony_cierr_no_txchan: 11508c2ecf20Sopenharmony_ci dma_release_channel(pl022->dma_rx_channel); 11518c2ecf20Sopenharmony_ci pl022->dma_rx_channel = NULL; 11528c2ecf20Sopenharmony_cierr_no_rxchan: 11538c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 11548c2ecf20Sopenharmony_ci "Failed to work in dma mode, work without dma!\n"); 11558c2ecf20Sopenharmony_ci return -ENODEV; 11568c2ecf20Sopenharmony_ci} 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_cistatic int pl022_dma_autoprobe(struct pl022 *pl022) 11598c2ecf20Sopenharmony_ci{ 11608c2ecf20Sopenharmony_ci struct device *dev = &pl022->adev->dev; 11618c2ecf20Sopenharmony_ci struct dma_chan *chan; 11628c2ecf20Sopenharmony_ci int err; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci /* automatically configure DMA channels from platform, normally using DT */ 11658c2ecf20Sopenharmony_ci chan = dma_request_chan(dev, "rx"); 11668c2ecf20Sopenharmony_ci if (IS_ERR(chan)) { 11678c2ecf20Sopenharmony_ci err = PTR_ERR(chan); 11688c2ecf20Sopenharmony_ci goto err_no_rxchan; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci pl022->dma_rx_channel = chan; 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci chan = dma_request_chan(dev, "tx"); 11748c2ecf20Sopenharmony_ci if (IS_ERR(chan)) { 11758c2ecf20Sopenharmony_ci err = PTR_ERR(chan); 11768c2ecf20Sopenharmony_ci goto err_no_txchan; 11778c2ecf20Sopenharmony_ci } 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci pl022->dma_tx_channel = chan; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); 11828c2ecf20Sopenharmony_ci if (!pl022->dummypage) { 11838c2ecf20Sopenharmony_ci err = -ENOMEM; 11848c2ecf20Sopenharmony_ci goto err_no_dummypage; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci return 0; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cierr_no_dummypage: 11908c2ecf20Sopenharmony_ci dma_release_channel(pl022->dma_tx_channel); 11918c2ecf20Sopenharmony_ci pl022->dma_tx_channel = NULL; 11928c2ecf20Sopenharmony_cierr_no_txchan: 11938c2ecf20Sopenharmony_ci dma_release_channel(pl022->dma_rx_channel); 11948c2ecf20Sopenharmony_ci pl022->dma_rx_channel = NULL; 11958c2ecf20Sopenharmony_cierr_no_rxchan: 11968c2ecf20Sopenharmony_ci return err; 11978c2ecf20Sopenharmony_ci} 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_cistatic void terminate_dma(struct pl022 *pl022) 12008c2ecf20Sopenharmony_ci{ 12018c2ecf20Sopenharmony_ci struct dma_chan *rxchan = pl022->dma_rx_channel; 12028c2ecf20Sopenharmony_ci struct dma_chan *txchan = pl022->dma_tx_channel; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci dmaengine_terminate_all(rxchan); 12058c2ecf20Sopenharmony_ci dmaengine_terminate_all(txchan); 12068c2ecf20Sopenharmony_ci unmap_free_dma_scatter(pl022); 12078c2ecf20Sopenharmony_ci pl022->dma_running = false; 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_cistatic void pl022_dma_remove(struct pl022 *pl022) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci if (pl022->dma_running) 12138c2ecf20Sopenharmony_ci terminate_dma(pl022); 12148c2ecf20Sopenharmony_ci if (pl022->dma_tx_channel) 12158c2ecf20Sopenharmony_ci dma_release_channel(pl022->dma_tx_channel); 12168c2ecf20Sopenharmony_ci if (pl022->dma_rx_channel) 12178c2ecf20Sopenharmony_ci dma_release_channel(pl022->dma_rx_channel); 12188c2ecf20Sopenharmony_ci kfree(pl022->dummypage); 12198c2ecf20Sopenharmony_ci} 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci#else 12228c2ecf20Sopenharmony_cistatic inline int configure_dma(struct pl022 *pl022) 12238c2ecf20Sopenharmony_ci{ 12248c2ecf20Sopenharmony_ci return -ENODEV; 12258c2ecf20Sopenharmony_ci} 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_cistatic inline int pl022_dma_autoprobe(struct pl022 *pl022) 12288c2ecf20Sopenharmony_ci{ 12298c2ecf20Sopenharmony_ci return 0; 12308c2ecf20Sopenharmony_ci} 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_cistatic inline int pl022_dma_probe(struct pl022 *pl022) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci return 0; 12358c2ecf20Sopenharmony_ci} 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic inline void pl022_dma_remove(struct pl022 *pl022) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci} 12408c2ecf20Sopenharmony_ci#endif 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci/** 12438c2ecf20Sopenharmony_ci * pl022_interrupt_handler - Interrupt handler for SSP controller 12448c2ecf20Sopenharmony_ci * @irq: IRQ number 12458c2ecf20Sopenharmony_ci * @dev_id: Local device data 12468c2ecf20Sopenharmony_ci * 12478c2ecf20Sopenharmony_ci * This function handles interrupts generated for an interrupt based transfer. 12488c2ecf20Sopenharmony_ci * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the 12498c2ecf20Sopenharmony_ci * current message's state as STATE_ERROR and schedule the tasklet 12508c2ecf20Sopenharmony_ci * pump_transfers which will do the postprocessing of the current message by 12518c2ecf20Sopenharmony_ci * calling giveback(). Otherwise it reads data from RX FIFO till there is no 12528c2ecf20Sopenharmony_ci * more data, and writes data in TX FIFO till it is not full. If we complete 12538c2ecf20Sopenharmony_ci * the transfer we move to the next transfer and schedule the tasklet. 12548c2ecf20Sopenharmony_ci */ 12558c2ecf20Sopenharmony_cistatic irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci struct pl022 *pl022 = dev_id; 12588c2ecf20Sopenharmony_ci struct spi_message *msg = pl022->cur_msg; 12598c2ecf20Sopenharmony_ci u16 irq_status = 0; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (unlikely(!msg)) { 12628c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 12638c2ecf20Sopenharmony_ci "bad message state in interrupt handler"); 12648c2ecf20Sopenharmony_ci /* Never fail */ 12658c2ecf20Sopenharmony_ci return IRQ_HANDLED; 12668c2ecf20Sopenharmony_ci } 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci /* Read the Interrupt Status Register */ 12698c2ecf20Sopenharmony_ci irq_status = readw(SSP_MIS(pl022->virtbase)); 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci if (unlikely(!irq_status)) 12728c2ecf20Sopenharmony_ci return IRQ_NONE; 12738c2ecf20Sopenharmony_ci 12748c2ecf20Sopenharmony_ci /* 12758c2ecf20Sopenharmony_ci * This handles the FIFO interrupts, the timeout 12768c2ecf20Sopenharmony_ci * interrupts are flatly ignored, they cannot be 12778c2ecf20Sopenharmony_ci * trusted. 12788c2ecf20Sopenharmony_ci */ 12798c2ecf20Sopenharmony_ci if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) { 12808c2ecf20Sopenharmony_ci /* 12818c2ecf20Sopenharmony_ci * Overrun interrupt - bail out since our Data has been 12828c2ecf20Sopenharmony_ci * corrupted 12838c2ecf20Sopenharmony_ci */ 12848c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, "FIFO overrun\n"); 12858c2ecf20Sopenharmony_ci if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF) 12868c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 12878c2ecf20Sopenharmony_ci "RXFIFO is full\n"); 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci /* 12908c2ecf20Sopenharmony_ci * Disable and clear interrupts, disable SSP, 12918c2ecf20Sopenharmony_ci * mark message with bad status so it can be 12928c2ecf20Sopenharmony_ci * retried. 12938c2ecf20Sopenharmony_ci */ 12948c2ecf20Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, 12958c2ecf20Sopenharmony_ci SSP_IMSC(pl022->virtbase)); 12968c2ecf20Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 12978c2ecf20Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & 12988c2ecf20Sopenharmony_ci (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); 12998c2ecf20Sopenharmony_ci msg->state = STATE_ERROR; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci /* Schedule message queue handler */ 13028c2ecf20Sopenharmony_ci tasklet_schedule(&pl022->pump_transfers); 13038c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13048c2ecf20Sopenharmony_ci } 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci readwriter(pl022); 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci if (pl022->tx == pl022->tx_end) { 13098c2ecf20Sopenharmony_ci /* Disable Transmit interrupt, enable receive interrupt */ 13108c2ecf20Sopenharmony_ci writew((readw(SSP_IMSC(pl022->virtbase)) & 13118c2ecf20Sopenharmony_ci ~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM, 13128c2ecf20Sopenharmony_ci SSP_IMSC(pl022->virtbase)); 13138c2ecf20Sopenharmony_ci } 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci /* 13168c2ecf20Sopenharmony_ci * Since all transactions must write as much as shall be read, 13178c2ecf20Sopenharmony_ci * we can conclude the entire transaction once RX is complete. 13188c2ecf20Sopenharmony_ci * At this point, all TX will always be finished. 13198c2ecf20Sopenharmony_ci */ 13208c2ecf20Sopenharmony_ci if (pl022->rx >= pl022->rx_end) { 13218c2ecf20Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, 13228c2ecf20Sopenharmony_ci SSP_IMSC(pl022->virtbase)); 13238c2ecf20Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 13248c2ecf20Sopenharmony_ci if (unlikely(pl022->rx > pl022->rx_end)) { 13258c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, "read %u surplus " 13268c2ecf20Sopenharmony_ci "bytes (did you request an odd " 13278c2ecf20Sopenharmony_ci "number of bytes on a 16bit bus?)\n", 13288c2ecf20Sopenharmony_ci (u32) (pl022->rx - pl022->rx_end)); 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci /* Update total bytes transferred */ 13318c2ecf20Sopenharmony_ci msg->actual_length += pl022->cur_transfer->len; 13328c2ecf20Sopenharmony_ci /* Move to next transfer */ 13338c2ecf20Sopenharmony_ci msg->state = next_transfer(pl022); 13348c2ecf20Sopenharmony_ci if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change) 13358c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 13368c2ecf20Sopenharmony_ci tasklet_schedule(&pl022->pump_transfers); 13378c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci return IRQ_HANDLED; 13418c2ecf20Sopenharmony_ci} 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci/* 13448c2ecf20Sopenharmony_ci * This sets up the pointers to memory for the next message to 13458c2ecf20Sopenharmony_ci * send out on the SPI bus. 13468c2ecf20Sopenharmony_ci */ 13478c2ecf20Sopenharmony_cistatic int set_up_next_transfer(struct pl022 *pl022, 13488c2ecf20Sopenharmony_ci struct spi_transfer *transfer) 13498c2ecf20Sopenharmony_ci{ 13508c2ecf20Sopenharmony_ci int residue; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci /* Sanity check the message for this bus width */ 13538c2ecf20Sopenharmony_ci residue = pl022->cur_transfer->len % pl022->cur_chip->n_bytes; 13548c2ecf20Sopenharmony_ci if (unlikely(residue != 0)) { 13558c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 13568c2ecf20Sopenharmony_ci "message of %u bytes to transmit but the current " 13578c2ecf20Sopenharmony_ci "chip bus has a data width of %u bytes!\n", 13588c2ecf20Sopenharmony_ci pl022->cur_transfer->len, 13598c2ecf20Sopenharmony_ci pl022->cur_chip->n_bytes); 13608c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, "skipping this message\n"); 13618c2ecf20Sopenharmony_ci return -EIO; 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci pl022->tx = (void *)transfer->tx_buf; 13648c2ecf20Sopenharmony_ci pl022->tx_end = pl022->tx + pl022->cur_transfer->len; 13658c2ecf20Sopenharmony_ci pl022->rx = (void *)transfer->rx_buf; 13668c2ecf20Sopenharmony_ci pl022->rx_end = pl022->rx + pl022->cur_transfer->len; 13678c2ecf20Sopenharmony_ci pl022->write = 13688c2ecf20Sopenharmony_ci pl022->tx ? pl022->cur_chip->write : WRITING_NULL; 13698c2ecf20Sopenharmony_ci pl022->read = pl022->rx ? pl022->cur_chip->read : READING_NULL; 13708c2ecf20Sopenharmony_ci return 0; 13718c2ecf20Sopenharmony_ci} 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci/** 13748c2ecf20Sopenharmony_ci * pump_transfers - Tasklet function which schedules next transfer 13758c2ecf20Sopenharmony_ci * when running in interrupt or DMA transfer mode. 13768c2ecf20Sopenharmony_ci * @data: SSP driver private data structure 13778c2ecf20Sopenharmony_ci * 13788c2ecf20Sopenharmony_ci */ 13798c2ecf20Sopenharmony_cistatic void pump_transfers(unsigned long data) 13808c2ecf20Sopenharmony_ci{ 13818c2ecf20Sopenharmony_ci struct pl022 *pl022 = (struct pl022 *) data; 13828c2ecf20Sopenharmony_ci struct spi_message *message = NULL; 13838c2ecf20Sopenharmony_ci struct spi_transfer *transfer = NULL; 13848c2ecf20Sopenharmony_ci struct spi_transfer *previous = NULL; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci /* Get current state information */ 13878c2ecf20Sopenharmony_ci message = pl022->cur_msg; 13888c2ecf20Sopenharmony_ci transfer = pl022->cur_transfer; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci /* Handle for abort */ 13918c2ecf20Sopenharmony_ci if (message->state == STATE_ERROR) { 13928c2ecf20Sopenharmony_ci message->status = -EIO; 13938c2ecf20Sopenharmony_ci giveback(pl022); 13948c2ecf20Sopenharmony_ci return; 13958c2ecf20Sopenharmony_ci } 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci /* Handle end of message */ 13988c2ecf20Sopenharmony_ci if (message->state == STATE_DONE) { 13998c2ecf20Sopenharmony_ci message->status = 0; 14008c2ecf20Sopenharmony_ci giveback(pl022); 14018c2ecf20Sopenharmony_ci return; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* Delay if requested at end of transfer before CS change */ 14058c2ecf20Sopenharmony_ci if (message->state == STATE_RUNNING) { 14068c2ecf20Sopenharmony_ci previous = list_entry(transfer->transfer_list.prev, 14078c2ecf20Sopenharmony_ci struct spi_transfer, 14088c2ecf20Sopenharmony_ci transfer_list); 14098c2ecf20Sopenharmony_ci /* 14108c2ecf20Sopenharmony_ci * FIXME: This runs in interrupt context. 14118c2ecf20Sopenharmony_ci * Is this really smart? 14128c2ecf20Sopenharmony_ci */ 14138c2ecf20Sopenharmony_ci spi_transfer_delay_exec(previous); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* Reselect chip select only if cs_change was requested */ 14168c2ecf20Sopenharmony_ci if (previous->cs_change) 14178c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 14188c2ecf20Sopenharmony_ci } else { 14198c2ecf20Sopenharmony_ci /* STATE_START */ 14208c2ecf20Sopenharmony_ci message->state = STATE_RUNNING; 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (set_up_next_transfer(pl022, transfer)) { 14248c2ecf20Sopenharmony_ci message->state = STATE_ERROR; 14258c2ecf20Sopenharmony_ci message->status = -EIO; 14268c2ecf20Sopenharmony_ci giveback(pl022); 14278c2ecf20Sopenharmony_ci return; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci /* Flush the FIFOs and let's go! */ 14308c2ecf20Sopenharmony_ci flush(pl022); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci if (pl022->cur_chip->enable_dma) { 14338c2ecf20Sopenharmony_ci if (configure_dma(pl022)) { 14348c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, 14358c2ecf20Sopenharmony_ci "configuration of DMA failed, fall back to interrupt mode\n"); 14368c2ecf20Sopenharmony_ci goto err_config_dma; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci return; 14398c2ecf20Sopenharmony_ci } 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_cierr_config_dma: 14428c2ecf20Sopenharmony_ci /* enable all interrupts except RX */ 14438c2ecf20Sopenharmony_ci writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase)); 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic void do_interrupt_dma_transfer(struct pl022 *pl022) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci /* 14498c2ecf20Sopenharmony_ci * Default is to enable all interrupts except RX - 14508c2ecf20Sopenharmony_ci * this will be enabled once TX is complete 14518c2ecf20Sopenharmony_ci */ 14528c2ecf20Sopenharmony_ci u32 irqflags = (u32)(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM); 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* Enable target chip, if not already active */ 14558c2ecf20Sopenharmony_ci if (!pl022->next_msg_cs_active) 14568c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (set_up_next_transfer(pl022, pl022->cur_transfer)) { 14598c2ecf20Sopenharmony_ci /* Error path */ 14608c2ecf20Sopenharmony_ci pl022->cur_msg->state = STATE_ERROR; 14618c2ecf20Sopenharmony_ci pl022->cur_msg->status = -EIO; 14628c2ecf20Sopenharmony_ci giveback(pl022); 14638c2ecf20Sopenharmony_ci return; 14648c2ecf20Sopenharmony_ci } 14658c2ecf20Sopenharmony_ci /* If we're using DMA, set up DMA here */ 14668c2ecf20Sopenharmony_ci if (pl022->cur_chip->enable_dma) { 14678c2ecf20Sopenharmony_ci /* Configure DMA transfer */ 14688c2ecf20Sopenharmony_ci if (configure_dma(pl022)) { 14698c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, 14708c2ecf20Sopenharmony_ci "configuration of DMA failed, fall back to interrupt mode\n"); 14718c2ecf20Sopenharmony_ci goto err_config_dma; 14728c2ecf20Sopenharmony_ci } 14738c2ecf20Sopenharmony_ci /* Disable interrupts in DMA mode, IRQ from DMA controller */ 14748c2ecf20Sopenharmony_ci irqflags = DISABLE_ALL_INTERRUPTS; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_cierr_config_dma: 14778c2ecf20Sopenharmony_ci /* Enable SSP, turn on interrupts */ 14788c2ecf20Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), 14798c2ecf20Sopenharmony_ci SSP_CR1(pl022->virtbase)); 14808c2ecf20Sopenharmony_ci writew(irqflags, SSP_IMSC(pl022->virtbase)); 14818c2ecf20Sopenharmony_ci} 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_cistatic void print_current_status(struct pl022 *pl022) 14848c2ecf20Sopenharmony_ci{ 14858c2ecf20Sopenharmony_ci u32 read_cr0; 14868c2ecf20Sopenharmony_ci u16 read_cr1, read_dmacr, read_sr; 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (pl022->vendor->extended_cr) 14898c2ecf20Sopenharmony_ci read_cr0 = readl(SSP_CR0(pl022->virtbase)); 14908c2ecf20Sopenharmony_ci else 14918c2ecf20Sopenharmony_ci read_cr0 = readw(SSP_CR0(pl022->virtbase)); 14928c2ecf20Sopenharmony_ci read_cr1 = readw(SSP_CR1(pl022->virtbase)); 14938c2ecf20Sopenharmony_ci read_dmacr = readw(SSP_DMACR(pl022->virtbase)); 14948c2ecf20Sopenharmony_ci read_sr = readw(SSP_SR(pl022->virtbase)); 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 CR0: %x\n", read_cr0); 14978c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 CR1: %x\n", read_cr1); 14988c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 DMACR: %x\n", read_dmacr); 14998c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 SR: %x\n", read_sr); 15008c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, 15018c2ecf20Sopenharmony_ci "spi-pl022 exp_fifo_level/fifodepth: %u/%d\n", 15028c2ecf20Sopenharmony_ci pl022->exp_fifo_level, 15038c2ecf20Sopenharmony_ci pl022->vendor->fifodepth); 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_cistatic void do_polling_transfer(struct pl022 *pl022) 15088c2ecf20Sopenharmony_ci{ 15098c2ecf20Sopenharmony_ci struct spi_message *message = NULL; 15108c2ecf20Sopenharmony_ci struct spi_transfer *transfer = NULL; 15118c2ecf20Sopenharmony_ci struct spi_transfer *previous = NULL; 15128c2ecf20Sopenharmony_ci unsigned long time, timeout; 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_ci message = pl022->cur_msg; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci while (message->state != STATE_DONE) { 15178c2ecf20Sopenharmony_ci /* Handle for abort */ 15188c2ecf20Sopenharmony_ci if (message->state == STATE_ERROR) 15198c2ecf20Sopenharmony_ci break; 15208c2ecf20Sopenharmony_ci transfer = pl022->cur_transfer; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci /* Delay if requested at end of transfer */ 15238c2ecf20Sopenharmony_ci if (message->state == STATE_RUNNING) { 15248c2ecf20Sopenharmony_ci previous = 15258c2ecf20Sopenharmony_ci list_entry(transfer->transfer_list.prev, 15268c2ecf20Sopenharmony_ci struct spi_transfer, transfer_list); 15278c2ecf20Sopenharmony_ci spi_transfer_delay_exec(previous); 15288c2ecf20Sopenharmony_ci if (previous->cs_change) 15298c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 15308c2ecf20Sopenharmony_ci } else { 15318c2ecf20Sopenharmony_ci /* STATE_START */ 15328c2ecf20Sopenharmony_ci message->state = STATE_RUNNING; 15338c2ecf20Sopenharmony_ci if (!pl022->next_msg_cs_active) 15348c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci /* Configuration Changing Per Transfer */ 15388c2ecf20Sopenharmony_ci if (set_up_next_transfer(pl022, transfer)) { 15398c2ecf20Sopenharmony_ci /* Error path */ 15408c2ecf20Sopenharmony_ci message->state = STATE_ERROR; 15418c2ecf20Sopenharmony_ci break; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci /* Flush FIFOs and enable SSP */ 15448c2ecf20Sopenharmony_ci flush(pl022); 15458c2ecf20Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), 15468c2ecf20Sopenharmony_ci SSP_CR1(pl022->virtbase)); 15478c2ecf20Sopenharmony_ci 15488c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n"); 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT); 15518c2ecf20Sopenharmony_ci while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) { 15528c2ecf20Sopenharmony_ci time = jiffies; 15538c2ecf20Sopenharmony_ci readwriter(pl022); 15548c2ecf20Sopenharmony_ci if (time_after(time, timeout)) { 15558c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, 15568c2ecf20Sopenharmony_ci "%s: timeout!\n", __func__); 15578c2ecf20Sopenharmony_ci message->state = STATE_TIMEOUT; 15588c2ecf20Sopenharmony_ci print_current_status(pl022); 15598c2ecf20Sopenharmony_ci goto out; 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci cpu_relax(); 15628c2ecf20Sopenharmony_ci } 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_ci /* Update total byte transferred */ 15658c2ecf20Sopenharmony_ci message->actual_length += pl022->cur_transfer->len; 15668c2ecf20Sopenharmony_ci /* Move to next transfer */ 15678c2ecf20Sopenharmony_ci message->state = next_transfer(pl022); 15688c2ecf20Sopenharmony_ci if (message->state != STATE_DONE 15698c2ecf20Sopenharmony_ci && pl022->cur_transfer->cs_change) 15708c2ecf20Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 15718c2ecf20Sopenharmony_ci } 15728c2ecf20Sopenharmony_ciout: 15738c2ecf20Sopenharmony_ci /* Handle end of message */ 15748c2ecf20Sopenharmony_ci if (message->state == STATE_DONE) 15758c2ecf20Sopenharmony_ci message->status = 0; 15768c2ecf20Sopenharmony_ci else if (message->state == STATE_TIMEOUT) 15778c2ecf20Sopenharmony_ci message->status = -EAGAIN; 15788c2ecf20Sopenharmony_ci else 15798c2ecf20Sopenharmony_ci message->status = -EIO; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci giveback(pl022); 15828c2ecf20Sopenharmony_ci return; 15838c2ecf20Sopenharmony_ci} 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_cistatic int pl022_transfer_one_message(struct spi_master *master, 15868c2ecf20Sopenharmony_ci struct spi_message *msg) 15878c2ecf20Sopenharmony_ci{ 15888c2ecf20Sopenharmony_ci struct pl022 *pl022 = spi_master_get_devdata(master); 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci /* Initial message state */ 15918c2ecf20Sopenharmony_ci pl022->cur_msg = msg; 15928c2ecf20Sopenharmony_ci msg->state = STATE_START; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci pl022->cur_transfer = list_entry(msg->transfers.next, 15958c2ecf20Sopenharmony_ci struct spi_transfer, transfer_list); 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci /* Setup the SPI using the per chip configuration */ 15988c2ecf20Sopenharmony_ci pl022->cur_chip = spi_get_ctldata(msg->spi); 15998c2ecf20Sopenharmony_ci pl022->cur_cs = pl022->chipselects[msg->spi->chip_select]; 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci restore_state(pl022); 16028c2ecf20Sopenharmony_ci flush(pl022); 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci if (pl022->cur_chip->xfer_type == POLLING_TRANSFER) 16058c2ecf20Sopenharmony_ci do_polling_transfer(pl022); 16068c2ecf20Sopenharmony_ci else 16078c2ecf20Sopenharmony_ci do_interrupt_dma_transfer(pl022); 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci return 0; 16108c2ecf20Sopenharmony_ci} 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_cistatic int pl022_unprepare_transfer_hardware(struct spi_master *master) 16138c2ecf20Sopenharmony_ci{ 16148c2ecf20Sopenharmony_ci struct pl022 *pl022 = spi_master_get_devdata(master); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci /* nothing more to do - disable spi/ssp and power off */ 16178c2ecf20Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & 16188c2ecf20Sopenharmony_ci (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci return 0; 16218c2ecf20Sopenharmony_ci} 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_cistatic int verify_controller_parameters(struct pl022 *pl022, 16248c2ecf20Sopenharmony_ci struct pl022_config_chip const *chip_info) 16258c2ecf20Sopenharmony_ci{ 16268c2ecf20Sopenharmony_ci if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI) 16278c2ecf20Sopenharmony_ci || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) { 16288c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16298c2ecf20Sopenharmony_ci "interface is configured incorrectly\n"); 16308c2ecf20Sopenharmony_ci return -EINVAL; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) && 16338c2ecf20Sopenharmony_ci (!pl022->vendor->unidir)) { 16348c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16358c2ecf20Sopenharmony_ci "unidirectional mode not supported in this " 16368c2ecf20Sopenharmony_ci "hardware version\n"); 16378c2ecf20Sopenharmony_ci return -EINVAL; 16388c2ecf20Sopenharmony_ci } 16398c2ecf20Sopenharmony_ci if ((chip_info->hierarchy != SSP_MASTER) 16408c2ecf20Sopenharmony_ci && (chip_info->hierarchy != SSP_SLAVE)) { 16418c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16428c2ecf20Sopenharmony_ci "hierarchy is configured incorrectly\n"); 16438c2ecf20Sopenharmony_ci return -EINVAL; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci if ((chip_info->com_mode != INTERRUPT_TRANSFER) 16468c2ecf20Sopenharmony_ci && (chip_info->com_mode != DMA_TRANSFER) 16478c2ecf20Sopenharmony_ci && (chip_info->com_mode != POLLING_TRANSFER)) { 16488c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16498c2ecf20Sopenharmony_ci "Communication mode is configured incorrectly\n"); 16508c2ecf20Sopenharmony_ci return -EINVAL; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci switch (chip_info->rx_lev_trig) { 16538c2ecf20Sopenharmony_ci case SSP_RX_1_OR_MORE_ELEM: 16548c2ecf20Sopenharmony_ci case SSP_RX_4_OR_MORE_ELEM: 16558c2ecf20Sopenharmony_ci case SSP_RX_8_OR_MORE_ELEM: 16568c2ecf20Sopenharmony_ci /* These are always OK, all variants can handle this */ 16578c2ecf20Sopenharmony_ci break; 16588c2ecf20Sopenharmony_ci case SSP_RX_16_OR_MORE_ELEM: 16598c2ecf20Sopenharmony_ci if (pl022->vendor->fifodepth < 16) { 16608c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16618c2ecf20Sopenharmony_ci "RX FIFO Trigger Level is configured incorrectly\n"); 16628c2ecf20Sopenharmony_ci return -EINVAL; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci break; 16658c2ecf20Sopenharmony_ci case SSP_RX_32_OR_MORE_ELEM: 16668c2ecf20Sopenharmony_ci if (pl022->vendor->fifodepth < 32) { 16678c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16688c2ecf20Sopenharmony_ci "RX FIFO Trigger Level is configured incorrectly\n"); 16698c2ecf20Sopenharmony_ci return -EINVAL; 16708c2ecf20Sopenharmony_ci } 16718c2ecf20Sopenharmony_ci break; 16728c2ecf20Sopenharmony_ci default: 16738c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16748c2ecf20Sopenharmony_ci "RX FIFO Trigger Level is configured incorrectly\n"); 16758c2ecf20Sopenharmony_ci return -EINVAL; 16768c2ecf20Sopenharmony_ci } 16778c2ecf20Sopenharmony_ci switch (chip_info->tx_lev_trig) { 16788c2ecf20Sopenharmony_ci case SSP_TX_1_OR_MORE_EMPTY_LOC: 16798c2ecf20Sopenharmony_ci case SSP_TX_4_OR_MORE_EMPTY_LOC: 16808c2ecf20Sopenharmony_ci case SSP_TX_8_OR_MORE_EMPTY_LOC: 16818c2ecf20Sopenharmony_ci /* These are always OK, all variants can handle this */ 16828c2ecf20Sopenharmony_ci break; 16838c2ecf20Sopenharmony_ci case SSP_TX_16_OR_MORE_EMPTY_LOC: 16848c2ecf20Sopenharmony_ci if (pl022->vendor->fifodepth < 16) { 16858c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16868c2ecf20Sopenharmony_ci "TX FIFO Trigger Level is configured incorrectly\n"); 16878c2ecf20Sopenharmony_ci return -EINVAL; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci break; 16908c2ecf20Sopenharmony_ci case SSP_TX_32_OR_MORE_EMPTY_LOC: 16918c2ecf20Sopenharmony_ci if (pl022->vendor->fifodepth < 32) { 16928c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16938c2ecf20Sopenharmony_ci "TX FIFO Trigger Level is configured incorrectly\n"); 16948c2ecf20Sopenharmony_ci return -EINVAL; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci break; 16978c2ecf20Sopenharmony_ci default: 16988c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 16998c2ecf20Sopenharmony_ci "TX FIFO Trigger Level is configured incorrectly\n"); 17008c2ecf20Sopenharmony_ci return -EINVAL; 17018c2ecf20Sopenharmony_ci } 17028c2ecf20Sopenharmony_ci if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) { 17038c2ecf20Sopenharmony_ci if ((chip_info->ctrl_len < SSP_BITS_4) 17048c2ecf20Sopenharmony_ci || (chip_info->ctrl_len > SSP_BITS_32)) { 17058c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 17068c2ecf20Sopenharmony_ci "CTRL LEN is configured incorrectly\n"); 17078c2ecf20Sopenharmony_ci return -EINVAL; 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO) 17108c2ecf20Sopenharmony_ci && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) { 17118c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 17128c2ecf20Sopenharmony_ci "Wait State is configured incorrectly\n"); 17138c2ecf20Sopenharmony_ci return -EINVAL; 17148c2ecf20Sopenharmony_ci } 17158c2ecf20Sopenharmony_ci /* Half duplex is only available in the ST Micro version */ 17168c2ecf20Sopenharmony_ci if (pl022->vendor->extended_cr) { 17178c2ecf20Sopenharmony_ci if ((chip_info->duplex != 17188c2ecf20Sopenharmony_ci SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) 17198c2ecf20Sopenharmony_ci && (chip_info->duplex != 17208c2ecf20Sopenharmony_ci SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) { 17218c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 17228c2ecf20Sopenharmony_ci "Microwire duplex mode is configured incorrectly\n"); 17238c2ecf20Sopenharmony_ci return -EINVAL; 17248c2ecf20Sopenharmony_ci } 17258c2ecf20Sopenharmony_ci } else { 17268c2ecf20Sopenharmony_ci if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) { 17278c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 17288c2ecf20Sopenharmony_ci "Microwire half duplex mode requested," 17298c2ecf20Sopenharmony_ci " but this is only available in the" 17308c2ecf20Sopenharmony_ci " ST version of PL022\n"); 17318c2ecf20Sopenharmony_ci return -EINVAL; 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci return 0; 17368c2ecf20Sopenharmony_ci} 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cistatic inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr) 17398c2ecf20Sopenharmony_ci{ 17408c2ecf20Sopenharmony_ci return rate / (cpsdvsr * (1 + scr)); 17418c2ecf20Sopenharmony_ci} 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_cistatic int calculate_effective_freq(struct pl022 *pl022, int freq, struct 17448c2ecf20Sopenharmony_ci ssp_clock_params * clk_freq) 17458c2ecf20Sopenharmony_ci{ 17468c2ecf20Sopenharmony_ci /* Lets calculate the frequency parameters */ 17478c2ecf20Sopenharmony_ci u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN; 17488c2ecf20Sopenharmony_ci u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0, 17498c2ecf20Sopenharmony_ci best_scr = 0, tmp, found = 0; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci rate = clk_get_rate(pl022->clk); 17528c2ecf20Sopenharmony_ci /* cpsdvscr = 2 & scr 0 */ 17538c2ecf20Sopenharmony_ci max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN); 17548c2ecf20Sopenharmony_ci /* cpsdvsr = 254 & scr = 255 */ 17558c2ecf20Sopenharmony_ci min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX); 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (freq > max_tclk) 17588c2ecf20Sopenharmony_ci dev_warn(&pl022->adev->dev, 17598c2ecf20Sopenharmony_ci "Max speed that can be programmed is %d Hz, you requested %d\n", 17608c2ecf20Sopenharmony_ci max_tclk, freq); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci if (freq < min_tclk) { 17638c2ecf20Sopenharmony_ci dev_err(&pl022->adev->dev, 17648c2ecf20Sopenharmony_ci "Requested frequency: %d Hz is less than minimum possible %d Hz\n", 17658c2ecf20Sopenharmony_ci freq, min_tclk); 17668c2ecf20Sopenharmony_ci return -EINVAL; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci /* 17708c2ecf20Sopenharmony_ci * best_freq will give closest possible available rate (<= requested 17718c2ecf20Sopenharmony_ci * freq) for all values of scr & cpsdvsr. 17728c2ecf20Sopenharmony_ci */ 17738c2ecf20Sopenharmony_ci while ((cpsdvsr <= CPSDVR_MAX) && !found) { 17748c2ecf20Sopenharmony_ci while (scr <= SCR_MAX) { 17758c2ecf20Sopenharmony_ci tmp = spi_rate(rate, cpsdvsr, scr); 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci if (tmp > freq) { 17788c2ecf20Sopenharmony_ci /* we need lower freq */ 17798c2ecf20Sopenharmony_ci scr++; 17808c2ecf20Sopenharmony_ci continue; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci /* 17848c2ecf20Sopenharmony_ci * If found exact value, mark found and break. 17858c2ecf20Sopenharmony_ci * If found more closer value, update and break. 17868c2ecf20Sopenharmony_ci */ 17878c2ecf20Sopenharmony_ci if (tmp > best_freq) { 17888c2ecf20Sopenharmony_ci best_freq = tmp; 17898c2ecf20Sopenharmony_ci best_cpsdvsr = cpsdvsr; 17908c2ecf20Sopenharmony_ci best_scr = scr; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci if (tmp == freq) 17938c2ecf20Sopenharmony_ci found = 1; 17948c2ecf20Sopenharmony_ci } 17958c2ecf20Sopenharmony_ci /* 17968c2ecf20Sopenharmony_ci * increased scr will give lower rates, which are not 17978c2ecf20Sopenharmony_ci * required 17988c2ecf20Sopenharmony_ci */ 17998c2ecf20Sopenharmony_ci break; 18008c2ecf20Sopenharmony_ci } 18018c2ecf20Sopenharmony_ci cpsdvsr += 2; 18028c2ecf20Sopenharmony_ci scr = SCR_MIN; 18038c2ecf20Sopenharmony_ci } 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci WARN(!best_freq, "pl022: Matching cpsdvsr and scr not found for %d Hz rate \n", 18068c2ecf20Sopenharmony_ci freq); 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF); 18098c2ecf20Sopenharmony_ci clk_freq->scr = (u8) (best_scr & 0xFF); 18108c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, 18118c2ecf20Sopenharmony_ci "SSP Target Frequency is: %u, Effective Frequency is %u\n", 18128c2ecf20Sopenharmony_ci freq, best_freq); 18138c2ecf20Sopenharmony_ci dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d\n", 18148c2ecf20Sopenharmony_ci clk_freq->cpsdvsr, clk_freq->scr); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci return 0; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci/* 18208c2ecf20Sopenharmony_ci * A piece of default chip info unless the platform 18218c2ecf20Sopenharmony_ci * supplies it. 18228c2ecf20Sopenharmony_ci */ 18238c2ecf20Sopenharmony_cistatic const struct pl022_config_chip pl022_default_chip_info = { 18248c2ecf20Sopenharmony_ci .com_mode = POLLING_TRANSFER, 18258c2ecf20Sopenharmony_ci .iface = SSP_INTERFACE_MOTOROLA_SPI, 18268c2ecf20Sopenharmony_ci .hierarchy = SSP_SLAVE, 18278c2ecf20Sopenharmony_ci .slave_tx_disable = DO_NOT_DRIVE_TX, 18288c2ecf20Sopenharmony_ci .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, 18298c2ecf20Sopenharmony_ci .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, 18308c2ecf20Sopenharmony_ci .ctrl_len = SSP_BITS_8, 18318c2ecf20Sopenharmony_ci .wait_state = SSP_MWIRE_WAIT_ZERO, 18328c2ecf20Sopenharmony_ci .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, 18338c2ecf20Sopenharmony_ci .cs_control = null_cs_control, 18348c2ecf20Sopenharmony_ci}; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci/** 18378c2ecf20Sopenharmony_ci * pl022_setup - setup function registered to SPI master framework 18388c2ecf20Sopenharmony_ci * @spi: spi device which is requesting setup 18398c2ecf20Sopenharmony_ci * 18408c2ecf20Sopenharmony_ci * This function is registered to the SPI framework for this SPI master 18418c2ecf20Sopenharmony_ci * controller. If it is the first time when setup is called by this device, 18428c2ecf20Sopenharmony_ci * this function will initialize the runtime state for this chip and save 18438c2ecf20Sopenharmony_ci * the same in the device structure. Else it will update the runtime info 18448c2ecf20Sopenharmony_ci * with the updated chip info. Nothing is really being written to the 18458c2ecf20Sopenharmony_ci * controller hardware here, that is not done until the actual transfer 18468c2ecf20Sopenharmony_ci * commence. 18478c2ecf20Sopenharmony_ci */ 18488c2ecf20Sopenharmony_cistatic int pl022_setup(struct spi_device *spi) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci struct pl022_config_chip const *chip_info; 18518c2ecf20Sopenharmony_ci struct pl022_config_chip chip_info_dt; 18528c2ecf20Sopenharmony_ci struct chip_data *chip; 18538c2ecf20Sopenharmony_ci struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0}; 18548c2ecf20Sopenharmony_ci int status = 0; 18558c2ecf20Sopenharmony_ci struct pl022 *pl022 = spi_master_get_devdata(spi->master); 18568c2ecf20Sopenharmony_ci unsigned int bits = spi->bits_per_word; 18578c2ecf20Sopenharmony_ci u32 tmp; 18588c2ecf20Sopenharmony_ci struct device_node *np = spi->dev.of_node; 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (!spi->max_speed_hz) 18618c2ecf20Sopenharmony_ci return -EINVAL; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci /* Get controller_state if one is supplied */ 18648c2ecf20Sopenharmony_ci chip = spi_get_ctldata(spi); 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci if (chip == NULL) { 18678c2ecf20Sopenharmony_ci chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); 18688c2ecf20Sopenharmony_ci if (!chip) 18698c2ecf20Sopenharmony_ci return -ENOMEM; 18708c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, 18718c2ecf20Sopenharmony_ci "allocated memory for controller's runtime state\n"); 18728c2ecf20Sopenharmony_ci } 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci /* Get controller data if one is supplied */ 18758c2ecf20Sopenharmony_ci chip_info = spi->controller_data; 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci if (chip_info == NULL) { 18788c2ecf20Sopenharmony_ci if (np) { 18798c2ecf20Sopenharmony_ci chip_info_dt = pl022_default_chip_info; 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci chip_info_dt.hierarchy = SSP_MASTER; 18828c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,interface", 18838c2ecf20Sopenharmony_ci &chip_info_dt.iface); 18848c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,com-mode", 18858c2ecf20Sopenharmony_ci &chip_info_dt.com_mode); 18868c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,rx-level-trig", 18878c2ecf20Sopenharmony_ci &chip_info_dt.rx_lev_trig); 18888c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,tx-level-trig", 18898c2ecf20Sopenharmony_ci &chip_info_dt.tx_lev_trig); 18908c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,ctrl-len", 18918c2ecf20Sopenharmony_ci &chip_info_dt.ctrl_len); 18928c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,wait-state", 18938c2ecf20Sopenharmony_ci &chip_info_dt.wait_state); 18948c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,duplex", 18958c2ecf20Sopenharmony_ci &chip_info_dt.duplex); 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci chip_info = &chip_info_dt; 18988c2ecf20Sopenharmony_ci } else { 18998c2ecf20Sopenharmony_ci chip_info = &pl022_default_chip_info; 19008c2ecf20Sopenharmony_ci /* spi_board_info.controller_data not is supplied */ 19018c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, 19028c2ecf20Sopenharmony_ci "using default controller_data settings\n"); 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci } else 19058c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, 19068c2ecf20Sopenharmony_ci "using user supplied controller_data settings\n"); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci /* 19098c2ecf20Sopenharmony_ci * We can override with custom divisors, else we use the board 19108c2ecf20Sopenharmony_ci * frequency setting 19118c2ecf20Sopenharmony_ci */ 19128c2ecf20Sopenharmony_ci if ((0 == chip_info->clk_freq.cpsdvsr) 19138c2ecf20Sopenharmony_ci && (0 == chip_info->clk_freq.scr)) { 19148c2ecf20Sopenharmony_ci status = calculate_effective_freq(pl022, 19158c2ecf20Sopenharmony_ci spi->max_speed_hz, 19168c2ecf20Sopenharmony_ci &clk_freq); 19178c2ecf20Sopenharmony_ci if (status < 0) 19188c2ecf20Sopenharmony_ci goto err_config_params; 19198c2ecf20Sopenharmony_ci } else { 19208c2ecf20Sopenharmony_ci memcpy(&clk_freq, &chip_info->clk_freq, sizeof(clk_freq)); 19218c2ecf20Sopenharmony_ci if ((clk_freq.cpsdvsr % 2) != 0) 19228c2ecf20Sopenharmony_ci clk_freq.cpsdvsr = 19238c2ecf20Sopenharmony_ci clk_freq.cpsdvsr - 1; 19248c2ecf20Sopenharmony_ci } 19258c2ecf20Sopenharmony_ci if ((clk_freq.cpsdvsr < CPSDVR_MIN) 19268c2ecf20Sopenharmony_ci || (clk_freq.cpsdvsr > CPSDVR_MAX)) { 19278c2ecf20Sopenharmony_ci status = -EINVAL; 19288c2ecf20Sopenharmony_ci dev_err(&spi->dev, 19298c2ecf20Sopenharmony_ci "cpsdvsr is configured incorrectly\n"); 19308c2ecf20Sopenharmony_ci goto err_config_params; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_ci status = verify_controller_parameters(pl022, chip_info); 19348c2ecf20Sopenharmony_ci if (status) { 19358c2ecf20Sopenharmony_ci dev_err(&spi->dev, "controller data is incorrect"); 19368c2ecf20Sopenharmony_ci goto err_config_params; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci pl022->rx_lev_trig = chip_info->rx_lev_trig; 19408c2ecf20Sopenharmony_ci pl022->tx_lev_trig = chip_info->tx_lev_trig; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci /* Now set controller state based on controller data */ 19438c2ecf20Sopenharmony_ci chip->xfer_type = chip_info->com_mode; 19448c2ecf20Sopenharmony_ci if (!chip_info->cs_control) { 19458c2ecf20Sopenharmony_ci chip->cs_control = null_cs_control; 19468c2ecf20Sopenharmony_ci if (!gpio_is_valid(pl022->chipselects[spi->chip_select])) 19478c2ecf20Sopenharmony_ci dev_warn(&spi->dev, 19488c2ecf20Sopenharmony_ci "invalid chip select\n"); 19498c2ecf20Sopenharmony_ci } else 19508c2ecf20Sopenharmony_ci chip->cs_control = chip_info->cs_control; 19518c2ecf20Sopenharmony_ci 19528c2ecf20Sopenharmony_ci /* Check bits per word with vendor specific range */ 19538c2ecf20Sopenharmony_ci if ((bits <= 3) || (bits > pl022->vendor->max_bpw)) { 19548c2ecf20Sopenharmony_ci status = -ENOTSUPP; 19558c2ecf20Sopenharmony_ci dev_err(&spi->dev, "illegal data size for this controller!\n"); 19568c2ecf20Sopenharmony_ci dev_err(&spi->dev, "This controller can only handle 4 <= n <= %d bit words\n", 19578c2ecf20Sopenharmony_ci pl022->vendor->max_bpw); 19588c2ecf20Sopenharmony_ci goto err_config_params; 19598c2ecf20Sopenharmony_ci } else if (bits <= 8) { 19608c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "4 <= n <=8 bits per word\n"); 19618c2ecf20Sopenharmony_ci chip->n_bytes = 1; 19628c2ecf20Sopenharmony_ci chip->read = READING_U8; 19638c2ecf20Sopenharmony_ci chip->write = WRITING_U8; 19648c2ecf20Sopenharmony_ci } else if (bits <= 16) { 19658c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n"); 19668c2ecf20Sopenharmony_ci chip->n_bytes = 2; 19678c2ecf20Sopenharmony_ci chip->read = READING_U16; 19688c2ecf20Sopenharmony_ci chip->write = WRITING_U16; 19698c2ecf20Sopenharmony_ci } else { 19708c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n"); 19718c2ecf20Sopenharmony_ci chip->n_bytes = 4; 19728c2ecf20Sopenharmony_ci chip->read = READING_U32; 19738c2ecf20Sopenharmony_ci chip->write = WRITING_U32; 19748c2ecf20Sopenharmony_ci } 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci /* Now Initialize all register settings required for this chip */ 19778c2ecf20Sopenharmony_ci chip->cr0 = 0; 19788c2ecf20Sopenharmony_ci chip->cr1 = 0; 19798c2ecf20Sopenharmony_ci chip->dmacr = 0; 19808c2ecf20Sopenharmony_ci chip->cpsr = 0; 19818c2ecf20Sopenharmony_ci if ((chip_info->com_mode == DMA_TRANSFER) 19828c2ecf20Sopenharmony_ci && ((pl022->master_info)->enable_dma)) { 19838c2ecf20Sopenharmony_ci chip->enable_dma = true; 19848c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "DMA mode set in controller state\n"); 19858c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, 19868c2ecf20Sopenharmony_ci SSP_DMACR_MASK_RXDMAE, 0); 19878c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, 19888c2ecf20Sopenharmony_ci SSP_DMACR_MASK_TXDMAE, 1); 19898c2ecf20Sopenharmony_ci } else { 19908c2ecf20Sopenharmony_ci chip->enable_dma = false; 19918c2ecf20Sopenharmony_ci dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n"); 19928c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED, 19938c2ecf20Sopenharmony_ci SSP_DMACR_MASK_RXDMAE, 0); 19948c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED, 19958c2ecf20Sopenharmony_ci SSP_DMACR_MASK_TXDMAE, 1); 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci chip->cpsr = clk_freq.cpsdvsr; 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_ci /* Special setup for the ST micro extended control registers */ 20018c2ecf20Sopenharmony_ci if (pl022->vendor->extended_cr) { 20028c2ecf20Sopenharmony_ci u32 etx; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci if (pl022->vendor->pl023) { 20058c2ecf20Sopenharmony_ci /* These bits are only in the PL023 */ 20068c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay, 20078c2ecf20Sopenharmony_ci SSP_CR1_MASK_FBCLKDEL_ST, 13); 20088c2ecf20Sopenharmony_ci } else { 20098c2ecf20Sopenharmony_ci /* These bits are in the PL022 but not PL023 */ 20108c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->duplex, 20118c2ecf20Sopenharmony_ci SSP_CR0_MASK_HALFDUP_ST, 5); 20128c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, 20138c2ecf20Sopenharmony_ci SSP_CR0_MASK_CSS_ST, 16); 20148c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->iface, 20158c2ecf20Sopenharmony_ci SSP_CR0_MASK_FRF_ST, 21); 20168c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, 20178c2ecf20Sopenharmony_ci SSP_CR1_MASK_MWAIT_ST, 6); 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, bits - 1, 20208c2ecf20Sopenharmony_ci SSP_CR0_MASK_DSS_ST, 0); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci if (spi->mode & SPI_LSB_FIRST) { 20238c2ecf20Sopenharmony_ci tmp = SSP_RX_LSB; 20248c2ecf20Sopenharmony_ci etx = SSP_TX_LSB; 20258c2ecf20Sopenharmony_ci } else { 20268c2ecf20Sopenharmony_ci tmp = SSP_RX_MSB; 20278c2ecf20Sopenharmony_ci etx = SSP_TX_MSB; 20288c2ecf20Sopenharmony_ci } 20298c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_RENDN_ST, 4); 20308c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, etx, SSP_CR1_MASK_TENDN_ST, 5); 20318c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, 20328c2ecf20Sopenharmony_ci SSP_CR1_MASK_RXIFLSEL_ST, 7); 20338c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, 20348c2ecf20Sopenharmony_ci SSP_CR1_MASK_TXIFLSEL_ST, 10); 20358c2ecf20Sopenharmony_ci } else { 20368c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, bits - 1, 20378c2ecf20Sopenharmony_ci SSP_CR0_MASK_DSS, 0); 20388c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->iface, 20398c2ecf20Sopenharmony_ci SSP_CR0_MASK_FRF, 4); 20408c2ecf20Sopenharmony_ci } 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci /* Stuff that is common for all versions */ 20438c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPOL) 20448c2ecf20Sopenharmony_ci tmp = SSP_CLK_POL_IDLE_HIGH; 20458c2ecf20Sopenharmony_ci else 20468c2ecf20Sopenharmony_ci tmp = SSP_CLK_POL_IDLE_LOW; 20478c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci if (spi->mode & SPI_CPHA) 20508c2ecf20Sopenharmony_ci tmp = SSP_CLK_SECOND_EDGE; 20518c2ecf20Sopenharmony_ci else 20528c2ecf20Sopenharmony_ci tmp = SSP_CLK_FIRST_EDGE; 20538c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7); 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8); 20568c2ecf20Sopenharmony_ci /* Loopback is available on all versions except PL023 */ 20578c2ecf20Sopenharmony_ci if (pl022->vendor->loopback) { 20588c2ecf20Sopenharmony_ci if (spi->mode & SPI_LOOP) 20598c2ecf20Sopenharmony_ci tmp = LOOPBACK_ENABLED; 20608c2ecf20Sopenharmony_ci else 20618c2ecf20Sopenharmony_ci tmp = LOOPBACK_DISABLED; 20628c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_LBM, 0); 20638c2ecf20Sopenharmony_ci } 20648c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1); 20658c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2); 20668c2ecf20Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 20678c2ecf20Sopenharmony_ci 3); 20688c2ecf20Sopenharmony_ci 20698c2ecf20Sopenharmony_ci /* Save controller_state */ 20708c2ecf20Sopenharmony_ci spi_set_ctldata(spi, chip); 20718c2ecf20Sopenharmony_ci return status; 20728c2ecf20Sopenharmony_ci err_config_params: 20738c2ecf20Sopenharmony_ci spi_set_ctldata(spi, NULL); 20748c2ecf20Sopenharmony_ci kfree(chip); 20758c2ecf20Sopenharmony_ci return status; 20768c2ecf20Sopenharmony_ci} 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci/** 20798c2ecf20Sopenharmony_ci * pl022_cleanup - cleanup function registered to SPI master framework 20808c2ecf20Sopenharmony_ci * @spi: spi device which is requesting cleanup 20818c2ecf20Sopenharmony_ci * 20828c2ecf20Sopenharmony_ci * This function is registered to the SPI framework for this SPI master 20838c2ecf20Sopenharmony_ci * controller. It will free the runtime state of chip. 20848c2ecf20Sopenharmony_ci */ 20858c2ecf20Sopenharmony_cistatic void pl022_cleanup(struct spi_device *spi) 20868c2ecf20Sopenharmony_ci{ 20878c2ecf20Sopenharmony_ci struct chip_data *chip = spi_get_ctldata(spi); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci spi_set_ctldata(spi, NULL); 20908c2ecf20Sopenharmony_ci kfree(chip); 20918c2ecf20Sopenharmony_ci} 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_cistatic struct pl022_ssp_controller * 20948c2ecf20Sopenharmony_cipl022_platform_data_dt_get(struct device *dev) 20958c2ecf20Sopenharmony_ci{ 20968c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 20978c2ecf20Sopenharmony_ci struct pl022_ssp_controller *pd; 20988c2ecf20Sopenharmony_ci u32 tmp = 0; 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci if (!np) { 21018c2ecf20Sopenharmony_ci dev_err(dev, "no dt node defined\n"); 21028c2ecf20Sopenharmony_ci return NULL; 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL); 21068c2ecf20Sopenharmony_ci if (!pd) 21078c2ecf20Sopenharmony_ci return NULL; 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci pd->bus_id = -1; 21108c2ecf20Sopenharmony_ci pd->enable_dma = 1; 21118c2ecf20Sopenharmony_ci of_property_read_u32(np, "num-cs", &tmp); 21128c2ecf20Sopenharmony_ci pd->num_chipselect = tmp; 21138c2ecf20Sopenharmony_ci of_property_read_u32(np, "pl022,autosuspend-delay", 21148c2ecf20Sopenharmony_ci &pd->autosuspend_delay); 21158c2ecf20Sopenharmony_ci pd->rt = of_property_read_bool(np, "pl022,rt"); 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci return pd; 21188c2ecf20Sopenharmony_ci} 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_cistatic int pl022_probe(struct amba_device *adev, const struct amba_id *id) 21218c2ecf20Sopenharmony_ci{ 21228c2ecf20Sopenharmony_ci struct device *dev = &adev->dev; 21238c2ecf20Sopenharmony_ci struct pl022_ssp_controller *platform_info = 21248c2ecf20Sopenharmony_ci dev_get_platdata(&adev->dev); 21258c2ecf20Sopenharmony_ci struct spi_master *master; 21268c2ecf20Sopenharmony_ci struct pl022 *pl022 = NULL; /*Data for this driver */ 21278c2ecf20Sopenharmony_ci struct device_node *np = adev->dev.of_node; 21288c2ecf20Sopenharmony_ci int status = 0, i, num_cs; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci dev_info(&adev->dev, 21318c2ecf20Sopenharmony_ci "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); 21328c2ecf20Sopenharmony_ci if (!platform_info && IS_ENABLED(CONFIG_OF)) 21338c2ecf20Sopenharmony_ci platform_info = pl022_platform_data_dt_get(dev); 21348c2ecf20Sopenharmony_ci 21358c2ecf20Sopenharmony_ci if (!platform_info) { 21368c2ecf20Sopenharmony_ci dev_err(dev, "probe: no platform data defined\n"); 21378c2ecf20Sopenharmony_ci return -ENODEV; 21388c2ecf20Sopenharmony_ci } 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci if (platform_info->num_chipselect) { 21418c2ecf20Sopenharmony_ci num_cs = platform_info->num_chipselect; 21428c2ecf20Sopenharmony_ci } else { 21438c2ecf20Sopenharmony_ci dev_err(dev, "probe: no chip select defined\n"); 21448c2ecf20Sopenharmony_ci return -ENODEV; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* Allocate master with space for data */ 21488c2ecf20Sopenharmony_ci master = spi_alloc_master(dev, sizeof(struct pl022)); 21498c2ecf20Sopenharmony_ci if (master == NULL) { 21508c2ecf20Sopenharmony_ci dev_err(&adev->dev, "probe - cannot alloc SPI master\n"); 21518c2ecf20Sopenharmony_ci return -ENOMEM; 21528c2ecf20Sopenharmony_ci } 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci pl022 = spi_master_get_devdata(master); 21558c2ecf20Sopenharmony_ci pl022->master = master; 21568c2ecf20Sopenharmony_ci pl022->master_info = platform_info; 21578c2ecf20Sopenharmony_ci pl022->adev = adev; 21588c2ecf20Sopenharmony_ci pl022->vendor = id->data; 21598c2ecf20Sopenharmony_ci pl022->chipselects = devm_kcalloc(dev, num_cs, sizeof(int), 21608c2ecf20Sopenharmony_ci GFP_KERNEL); 21618c2ecf20Sopenharmony_ci if (!pl022->chipselects) { 21628c2ecf20Sopenharmony_ci status = -ENOMEM; 21638c2ecf20Sopenharmony_ci goto err_no_mem; 21648c2ecf20Sopenharmony_ci } 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci /* 21678c2ecf20Sopenharmony_ci * Bus Number Which has been Assigned to this SSP controller 21688c2ecf20Sopenharmony_ci * on this board 21698c2ecf20Sopenharmony_ci */ 21708c2ecf20Sopenharmony_ci master->bus_num = platform_info->bus_id; 21718c2ecf20Sopenharmony_ci master->num_chipselect = num_cs; 21728c2ecf20Sopenharmony_ci master->cleanup = pl022_cleanup; 21738c2ecf20Sopenharmony_ci master->setup = pl022_setup; 21748c2ecf20Sopenharmony_ci master->auto_runtime_pm = true; 21758c2ecf20Sopenharmony_ci master->transfer_one_message = pl022_transfer_one_message; 21768c2ecf20Sopenharmony_ci master->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; 21778c2ecf20Sopenharmony_ci master->rt = platform_info->rt; 21788c2ecf20Sopenharmony_ci master->dev.of_node = dev->of_node; 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci if (platform_info->num_chipselect && platform_info->chipselects) { 21818c2ecf20Sopenharmony_ci for (i = 0; i < num_cs; i++) 21828c2ecf20Sopenharmony_ci pl022->chipselects[i] = platform_info->chipselects[i]; 21838c2ecf20Sopenharmony_ci } else if (pl022->vendor->internal_cs_ctrl) { 21848c2ecf20Sopenharmony_ci for (i = 0; i < num_cs; i++) 21858c2ecf20Sopenharmony_ci pl022->chipselects[i] = i; 21868c2ecf20Sopenharmony_ci } else if (IS_ENABLED(CONFIG_OF)) { 21878c2ecf20Sopenharmony_ci for (i = 0; i < num_cs; i++) { 21888c2ecf20Sopenharmony_ci int cs_gpio = of_get_named_gpio(np, "cs-gpios", i); 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci if (cs_gpio == -EPROBE_DEFER) { 21918c2ecf20Sopenharmony_ci status = -EPROBE_DEFER; 21928c2ecf20Sopenharmony_ci goto err_no_gpio; 21938c2ecf20Sopenharmony_ci } 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci pl022->chipselects[i] = cs_gpio; 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_ci if (gpio_is_valid(cs_gpio)) { 21988c2ecf20Sopenharmony_ci if (devm_gpio_request(dev, cs_gpio, "ssp-pl022")) 21998c2ecf20Sopenharmony_ci dev_err(&adev->dev, 22008c2ecf20Sopenharmony_ci "could not request %d gpio\n", 22018c2ecf20Sopenharmony_ci cs_gpio); 22028c2ecf20Sopenharmony_ci else if (gpio_direction_output(cs_gpio, 1)) 22038c2ecf20Sopenharmony_ci dev_err(&adev->dev, 22048c2ecf20Sopenharmony_ci "could not set gpio %d as output\n", 22058c2ecf20Sopenharmony_ci cs_gpio); 22068c2ecf20Sopenharmony_ci } 22078c2ecf20Sopenharmony_ci } 22088c2ecf20Sopenharmony_ci } 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci /* 22118c2ecf20Sopenharmony_ci * Supports mode 0-3, loopback, and active low CS. Transfers are 22128c2ecf20Sopenharmony_ci * always MS bit first on the original pl022. 22138c2ecf20Sopenharmony_ci */ 22148c2ecf20Sopenharmony_ci master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; 22158c2ecf20Sopenharmony_ci if (pl022->vendor->extended_cr) 22168c2ecf20Sopenharmony_ci master->mode_bits |= SPI_LSB_FIRST; 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci dev_dbg(&adev->dev, "BUSNO: %d\n", master->bus_num); 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci status = amba_request_regions(adev, NULL); 22218c2ecf20Sopenharmony_ci if (status) 22228c2ecf20Sopenharmony_ci goto err_no_ioregion; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci pl022->phybase = adev->res.start; 22258c2ecf20Sopenharmony_ci pl022->virtbase = devm_ioremap(dev, adev->res.start, 22268c2ecf20Sopenharmony_ci resource_size(&adev->res)); 22278c2ecf20Sopenharmony_ci if (pl022->virtbase == NULL) { 22288c2ecf20Sopenharmony_ci status = -ENOMEM; 22298c2ecf20Sopenharmony_ci goto err_no_ioremap; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ci dev_info(&adev->dev, "mapped registers from %pa to %p\n", 22328c2ecf20Sopenharmony_ci &adev->res.start, pl022->virtbase); 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci pl022->clk = devm_clk_get(&adev->dev, NULL); 22358c2ecf20Sopenharmony_ci if (IS_ERR(pl022->clk)) { 22368c2ecf20Sopenharmony_ci status = PTR_ERR(pl022->clk); 22378c2ecf20Sopenharmony_ci dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); 22388c2ecf20Sopenharmony_ci goto err_no_clk; 22398c2ecf20Sopenharmony_ci } 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci status = clk_prepare_enable(pl022->clk); 22428c2ecf20Sopenharmony_ci if (status) { 22438c2ecf20Sopenharmony_ci dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); 22448c2ecf20Sopenharmony_ci goto err_no_clk_en; 22458c2ecf20Sopenharmony_ci } 22468c2ecf20Sopenharmony_ci 22478c2ecf20Sopenharmony_ci /* Initialize transfer pump */ 22488c2ecf20Sopenharmony_ci tasklet_init(&pl022->pump_transfers, pump_transfers, 22498c2ecf20Sopenharmony_ci (unsigned long)pl022); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci /* Disable SSP */ 22528c2ecf20Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), 22538c2ecf20Sopenharmony_ci SSP_CR1(pl022->virtbase)); 22548c2ecf20Sopenharmony_ci load_ssp_default_config(pl022); 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, 22578c2ecf20Sopenharmony_ci 0, "pl022", pl022); 22588c2ecf20Sopenharmony_ci if (status < 0) { 22598c2ecf20Sopenharmony_ci dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); 22608c2ecf20Sopenharmony_ci goto err_no_irq; 22618c2ecf20Sopenharmony_ci } 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci /* Get DMA channels, try autoconfiguration first */ 22648c2ecf20Sopenharmony_ci status = pl022_dma_autoprobe(pl022); 22658c2ecf20Sopenharmony_ci if (status == -EPROBE_DEFER) { 22668c2ecf20Sopenharmony_ci dev_dbg(dev, "deferring probe to get DMA channel\n"); 22678c2ecf20Sopenharmony_ci goto err_no_irq; 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci /* If that failed, use channels from platform_info */ 22718c2ecf20Sopenharmony_ci if (status == 0) 22728c2ecf20Sopenharmony_ci platform_info->enable_dma = 1; 22738c2ecf20Sopenharmony_ci else if (platform_info->enable_dma) { 22748c2ecf20Sopenharmony_ci status = pl022_dma_probe(pl022); 22758c2ecf20Sopenharmony_ci if (status != 0) 22768c2ecf20Sopenharmony_ci platform_info->enable_dma = 0; 22778c2ecf20Sopenharmony_ci } 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci /* Register with the SPI framework */ 22808c2ecf20Sopenharmony_ci amba_set_drvdata(adev, pl022); 22818c2ecf20Sopenharmony_ci status = devm_spi_register_master(&adev->dev, master); 22828c2ecf20Sopenharmony_ci if (status != 0) { 22838c2ecf20Sopenharmony_ci dev_err(&adev->dev, 22848c2ecf20Sopenharmony_ci "probe - problem registering spi master\n"); 22858c2ecf20Sopenharmony_ci goto err_spi_register; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci dev_dbg(dev, "probe succeeded\n"); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci /* let runtime pm put suspend */ 22908c2ecf20Sopenharmony_ci if (platform_info->autosuspend_delay > 0) { 22918c2ecf20Sopenharmony_ci dev_info(&adev->dev, 22928c2ecf20Sopenharmony_ci "will use autosuspend for runtime pm, delay %dms\n", 22938c2ecf20Sopenharmony_ci platform_info->autosuspend_delay); 22948c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 22958c2ecf20Sopenharmony_ci platform_info->autosuspend_delay); 22968c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 22978c2ecf20Sopenharmony_ci } 22988c2ecf20Sopenharmony_ci pm_runtime_put(dev); 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_ci return 0; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci err_spi_register: 23038c2ecf20Sopenharmony_ci if (platform_info->enable_dma) 23048c2ecf20Sopenharmony_ci pl022_dma_remove(pl022); 23058c2ecf20Sopenharmony_ci err_no_irq: 23068c2ecf20Sopenharmony_ci clk_disable_unprepare(pl022->clk); 23078c2ecf20Sopenharmony_ci err_no_clk_en: 23088c2ecf20Sopenharmony_ci err_no_clk: 23098c2ecf20Sopenharmony_ci err_no_ioremap: 23108c2ecf20Sopenharmony_ci amba_release_regions(adev); 23118c2ecf20Sopenharmony_ci err_no_ioregion: 23128c2ecf20Sopenharmony_ci err_no_gpio: 23138c2ecf20Sopenharmony_ci err_no_mem: 23148c2ecf20Sopenharmony_ci spi_master_put(master); 23158c2ecf20Sopenharmony_ci return status; 23168c2ecf20Sopenharmony_ci} 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_cistatic void 23198c2ecf20Sopenharmony_cipl022_remove(struct amba_device *adev) 23208c2ecf20Sopenharmony_ci{ 23218c2ecf20Sopenharmony_ci struct pl022 *pl022 = amba_get_drvdata(adev); 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci if (!pl022) 23248c2ecf20Sopenharmony_ci return; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci /* 23278c2ecf20Sopenharmony_ci * undo pm_runtime_put() in probe. I assume that we're not 23288c2ecf20Sopenharmony_ci * accessing the primecell here. 23298c2ecf20Sopenharmony_ci */ 23308c2ecf20Sopenharmony_ci pm_runtime_get_noresume(&adev->dev); 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci load_ssp_default_config(pl022); 23338c2ecf20Sopenharmony_ci if (pl022->master_info->enable_dma) 23348c2ecf20Sopenharmony_ci pl022_dma_remove(pl022); 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci clk_disable_unprepare(pl022->clk); 23378c2ecf20Sopenharmony_ci amba_release_regions(adev); 23388c2ecf20Sopenharmony_ci tasklet_disable(&pl022->pump_transfers); 23398c2ecf20Sopenharmony_ci} 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 23428c2ecf20Sopenharmony_cistatic int pl022_suspend(struct device *dev) 23438c2ecf20Sopenharmony_ci{ 23448c2ecf20Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 23458c2ecf20Sopenharmony_ci int ret; 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci ret = spi_master_suspend(pl022->master); 23488c2ecf20Sopenharmony_ci if (ret) 23498c2ecf20Sopenharmony_ci return ret; 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 23528c2ecf20Sopenharmony_ci if (ret) { 23538c2ecf20Sopenharmony_ci spi_master_resume(pl022->master); 23548c2ecf20Sopenharmony_ci return ret; 23558c2ecf20Sopenharmony_ci } 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci dev_dbg(dev, "suspended\n"); 23608c2ecf20Sopenharmony_ci return 0; 23618c2ecf20Sopenharmony_ci} 23628c2ecf20Sopenharmony_ci 23638c2ecf20Sopenharmony_cistatic int pl022_resume(struct device *dev) 23648c2ecf20Sopenharmony_ci{ 23658c2ecf20Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 23668c2ecf20Sopenharmony_ci int ret; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci ret = pm_runtime_force_resume(dev); 23698c2ecf20Sopenharmony_ci if (ret) 23708c2ecf20Sopenharmony_ci dev_err(dev, "problem resuming\n"); 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci /* Start the queue running */ 23738c2ecf20Sopenharmony_ci ret = spi_master_resume(pl022->master); 23748c2ecf20Sopenharmony_ci if (!ret) 23758c2ecf20Sopenharmony_ci dev_dbg(dev, "resumed\n"); 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci return ret; 23788c2ecf20Sopenharmony_ci} 23798c2ecf20Sopenharmony_ci#endif 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 23828c2ecf20Sopenharmony_cistatic int pl022_runtime_suspend(struct device *dev) 23838c2ecf20Sopenharmony_ci{ 23848c2ecf20Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci clk_disable_unprepare(pl022->clk); 23878c2ecf20Sopenharmony_ci pinctrl_pm_select_idle_state(dev); 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_ci return 0; 23908c2ecf20Sopenharmony_ci} 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_cistatic int pl022_runtime_resume(struct device *dev) 23938c2ecf20Sopenharmony_ci{ 23948c2ecf20Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci pinctrl_pm_select_default_state(dev); 23978c2ecf20Sopenharmony_ci clk_prepare_enable(pl022->clk); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci return 0; 24008c2ecf20Sopenharmony_ci} 24018c2ecf20Sopenharmony_ci#endif 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_cistatic const struct dev_pm_ops pl022_dev_pm_ops = { 24048c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume) 24058c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) 24068c2ecf20Sopenharmony_ci}; 24078c2ecf20Sopenharmony_ci 24088c2ecf20Sopenharmony_cistatic struct vendor_data vendor_arm = { 24098c2ecf20Sopenharmony_ci .fifodepth = 8, 24108c2ecf20Sopenharmony_ci .max_bpw = 16, 24118c2ecf20Sopenharmony_ci .unidir = false, 24128c2ecf20Sopenharmony_ci .extended_cr = false, 24138c2ecf20Sopenharmony_ci .pl023 = false, 24148c2ecf20Sopenharmony_ci .loopback = true, 24158c2ecf20Sopenharmony_ci .internal_cs_ctrl = false, 24168c2ecf20Sopenharmony_ci}; 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_cistatic struct vendor_data vendor_st = { 24198c2ecf20Sopenharmony_ci .fifodepth = 32, 24208c2ecf20Sopenharmony_ci .max_bpw = 32, 24218c2ecf20Sopenharmony_ci .unidir = false, 24228c2ecf20Sopenharmony_ci .extended_cr = true, 24238c2ecf20Sopenharmony_ci .pl023 = false, 24248c2ecf20Sopenharmony_ci .loopback = true, 24258c2ecf20Sopenharmony_ci .internal_cs_ctrl = false, 24268c2ecf20Sopenharmony_ci}; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_cistatic struct vendor_data vendor_st_pl023 = { 24298c2ecf20Sopenharmony_ci .fifodepth = 32, 24308c2ecf20Sopenharmony_ci .max_bpw = 32, 24318c2ecf20Sopenharmony_ci .unidir = false, 24328c2ecf20Sopenharmony_ci .extended_cr = true, 24338c2ecf20Sopenharmony_ci .pl023 = true, 24348c2ecf20Sopenharmony_ci .loopback = false, 24358c2ecf20Sopenharmony_ci .internal_cs_ctrl = false, 24368c2ecf20Sopenharmony_ci}; 24378c2ecf20Sopenharmony_ci 24388c2ecf20Sopenharmony_cistatic struct vendor_data vendor_lsi = { 24398c2ecf20Sopenharmony_ci .fifodepth = 8, 24408c2ecf20Sopenharmony_ci .max_bpw = 16, 24418c2ecf20Sopenharmony_ci .unidir = false, 24428c2ecf20Sopenharmony_ci .extended_cr = false, 24438c2ecf20Sopenharmony_ci .pl023 = false, 24448c2ecf20Sopenharmony_ci .loopback = true, 24458c2ecf20Sopenharmony_ci .internal_cs_ctrl = true, 24468c2ecf20Sopenharmony_ci}; 24478c2ecf20Sopenharmony_ci 24488c2ecf20Sopenharmony_cistatic const struct amba_id pl022_ids[] = { 24498c2ecf20Sopenharmony_ci { 24508c2ecf20Sopenharmony_ci /* 24518c2ecf20Sopenharmony_ci * ARM PL022 variant, this has a 16bit wide 24528c2ecf20Sopenharmony_ci * and 8 locations deep TX/RX FIFO 24538c2ecf20Sopenharmony_ci */ 24548c2ecf20Sopenharmony_ci .id = 0x00041022, 24558c2ecf20Sopenharmony_ci .mask = 0x000fffff, 24568c2ecf20Sopenharmony_ci .data = &vendor_arm, 24578c2ecf20Sopenharmony_ci }, 24588c2ecf20Sopenharmony_ci { 24598c2ecf20Sopenharmony_ci /* 24608c2ecf20Sopenharmony_ci * ST Micro derivative, this has 32bit wide 24618c2ecf20Sopenharmony_ci * and 32 locations deep TX/RX FIFO 24628c2ecf20Sopenharmony_ci */ 24638c2ecf20Sopenharmony_ci .id = 0x01080022, 24648c2ecf20Sopenharmony_ci .mask = 0xffffffff, 24658c2ecf20Sopenharmony_ci .data = &vendor_st, 24668c2ecf20Sopenharmony_ci }, 24678c2ecf20Sopenharmony_ci { 24688c2ecf20Sopenharmony_ci /* 24698c2ecf20Sopenharmony_ci * ST-Ericsson derivative "PL023" (this is not 24708c2ecf20Sopenharmony_ci * an official ARM number), this is a PL022 SSP block 24718c2ecf20Sopenharmony_ci * stripped to SPI mode only, it has 32bit wide 24728c2ecf20Sopenharmony_ci * and 32 locations deep TX/RX FIFO but no extended 24738c2ecf20Sopenharmony_ci * CR0/CR1 register 24748c2ecf20Sopenharmony_ci */ 24758c2ecf20Sopenharmony_ci .id = 0x00080023, 24768c2ecf20Sopenharmony_ci .mask = 0xffffffff, 24778c2ecf20Sopenharmony_ci .data = &vendor_st_pl023, 24788c2ecf20Sopenharmony_ci }, 24798c2ecf20Sopenharmony_ci { 24808c2ecf20Sopenharmony_ci /* 24818c2ecf20Sopenharmony_ci * PL022 variant that has a chip select control register whih 24828c2ecf20Sopenharmony_ci * allows control of 5 output signals nCS[0:4]. 24838c2ecf20Sopenharmony_ci */ 24848c2ecf20Sopenharmony_ci .id = 0x000b6022, 24858c2ecf20Sopenharmony_ci .mask = 0x000fffff, 24868c2ecf20Sopenharmony_ci .data = &vendor_lsi, 24878c2ecf20Sopenharmony_ci }, 24888c2ecf20Sopenharmony_ci { 0, 0 }, 24898c2ecf20Sopenharmony_ci}; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(amba, pl022_ids); 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_cistatic struct amba_driver pl022_driver = { 24948c2ecf20Sopenharmony_ci .drv = { 24958c2ecf20Sopenharmony_ci .name = "ssp-pl022", 24968c2ecf20Sopenharmony_ci .pm = &pl022_dev_pm_ops, 24978c2ecf20Sopenharmony_ci }, 24988c2ecf20Sopenharmony_ci .id_table = pl022_ids, 24998c2ecf20Sopenharmony_ci .probe = pl022_probe, 25008c2ecf20Sopenharmony_ci .remove = pl022_remove, 25018c2ecf20Sopenharmony_ci}; 25028c2ecf20Sopenharmony_ci 25038c2ecf20Sopenharmony_cistatic int __init pl022_init(void) 25048c2ecf20Sopenharmony_ci{ 25058c2ecf20Sopenharmony_ci return amba_driver_register(&pl022_driver); 25068c2ecf20Sopenharmony_ci} 25078c2ecf20Sopenharmony_cisubsys_initcall(pl022_init); 25088c2ecf20Sopenharmony_ci 25098c2ecf20Sopenharmony_cistatic void __exit pl022_exit(void) 25108c2ecf20Sopenharmony_ci{ 25118c2ecf20Sopenharmony_ci amba_driver_unregister(&pl022_driver); 25128c2ecf20Sopenharmony_ci} 25138c2ecf20Sopenharmony_cimodule_exit(pl022_exit); 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ciMODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); 25168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PL022 SSP Controller Driver"); 25178c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2518