162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * A driver for the ARM PL022 PrimeCell SSP/SPI bus master. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2008-2012 ST-Ericsson AB 662306a36Sopenharmony_ci * Copyright (C) 2006 STMicroelectronics Pvt. Ltd. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Author: Linus Walleij <linus.walleij@stericsson.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Initial version inspired by: 1162306a36Sopenharmony_ci * linux-2.6.17-rc3-mm1/drivers/spi/pxa2xx_spi.c 1262306a36Sopenharmony_ci * Initial adoption to PL022 by: 1362306a36Sopenharmony_ci * Sachin Verma <sachin.verma@st.com> 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/init.h> 1762306a36Sopenharmony_ci#include <linux/module.h> 1862306a36Sopenharmony_ci#include <linux/device.h> 1962306a36Sopenharmony_ci#include <linux/ioport.h> 2062306a36Sopenharmony_ci#include <linux/errno.h> 2162306a36Sopenharmony_ci#include <linux/interrupt.h> 2262306a36Sopenharmony_ci#include <linux/spi/spi.h> 2362306a36Sopenharmony_ci#include <linux/delay.h> 2462306a36Sopenharmony_ci#include <linux/clk.h> 2562306a36Sopenharmony_ci#include <linux/err.h> 2662306a36Sopenharmony_ci#include <linux/amba/bus.h> 2762306a36Sopenharmony_ci#include <linux/amba/pl022.h> 2862306a36Sopenharmony_ci#include <linux/io.h> 2962306a36Sopenharmony_ci#include <linux/slab.h> 3062306a36Sopenharmony_ci#include <linux/dmaengine.h> 3162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 3262306a36Sopenharmony_ci#include <linux/scatterlist.h> 3362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3462306a36Sopenharmony_ci#include <linux/of.h> 3562306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * This macro is used to define some register default values. 3962306a36Sopenharmony_ci * reg is masked with mask, the OR:ed with an (again masked) 4062306a36Sopenharmony_ci * val shifted sb steps to the left. 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci#define SSP_WRITE_BITS(reg, val, mask, sb) \ 4362306a36Sopenharmony_ci ((reg) = (((reg) & ~(mask)) | (((val)<<(sb)) & (mask)))) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * This macro is also used to define some default values. 4762306a36Sopenharmony_ci * It will just shift val by sb steps to the left and mask 4862306a36Sopenharmony_ci * the result with mask. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci#define GEN_MASK_BITS(val, mask, sb) \ 5162306a36Sopenharmony_ci (((val)<<(sb)) & (mask)) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define DRIVE_TX 0 5462306a36Sopenharmony_ci#define DO_NOT_DRIVE_TX 1 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define DO_NOT_QUEUE_DMA 0 5762306a36Sopenharmony_ci#define QUEUE_DMA 1 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define RX_TRANSFER 1 6062306a36Sopenharmony_ci#define TX_TRANSFER 2 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* 6362306a36Sopenharmony_ci * Macros to access SSP Registers with their offsets 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci#define SSP_CR0(r) (r + 0x000) 6662306a36Sopenharmony_ci#define SSP_CR1(r) (r + 0x004) 6762306a36Sopenharmony_ci#define SSP_DR(r) (r + 0x008) 6862306a36Sopenharmony_ci#define SSP_SR(r) (r + 0x00C) 6962306a36Sopenharmony_ci#define SSP_CPSR(r) (r + 0x010) 7062306a36Sopenharmony_ci#define SSP_IMSC(r) (r + 0x014) 7162306a36Sopenharmony_ci#define SSP_RIS(r) (r + 0x018) 7262306a36Sopenharmony_ci#define SSP_MIS(r) (r + 0x01C) 7362306a36Sopenharmony_ci#define SSP_ICR(r) (r + 0x020) 7462306a36Sopenharmony_ci#define SSP_DMACR(r) (r + 0x024) 7562306a36Sopenharmony_ci#define SSP_CSR(r) (r + 0x030) /* vendor extension */ 7662306a36Sopenharmony_ci#define SSP_ITCR(r) (r + 0x080) 7762306a36Sopenharmony_ci#define SSP_ITIP(r) (r + 0x084) 7862306a36Sopenharmony_ci#define SSP_ITOP(r) (r + 0x088) 7962306a36Sopenharmony_ci#define SSP_TDR(r) (r + 0x08C) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define SSP_PID0(r) (r + 0xFE0) 8262306a36Sopenharmony_ci#define SSP_PID1(r) (r + 0xFE4) 8362306a36Sopenharmony_ci#define SSP_PID2(r) (r + 0xFE8) 8462306a36Sopenharmony_ci#define SSP_PID3(r) (r + 0xFEC) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define SSP_CID0(r) (r + 0xFF0) 8762306a36Sopenharmony_ci#define SSP_CID1(r) (r + 0xFF4) 8862306a36Sopenharmony_ci#define SSP_CID2(r) (r + 0xFF8) 8962306a36Sopenharmony_ci#define SSP_CID3(r) (r + 0xFFC) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * SSP Control Register 0 - SSP_CR0 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci#define SSP_CR0_MASK_DSS (0x0FUL << 0) 9562306a36Sopenharmony_ci#define SSP_CR0_MASK_FRF (0x3UL << 4) 9662306a36Sopenharmony_ci#define SSP_CR0_MASK_SPO (0x1UL << 6) 9762306a36Sopenharmony_ci#define SSP_CR0_MASK_SPH (0x1UL << 7) 9862306a36Sopenharmony_ci#define SSP_CR0_MASK_SCR (0xFFUL << 8) 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * The ST version of this block moves som bits 10262306a36Sopenharmony_ci * in SSP_CR0 and extends it to 32 bits 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci#define SSP_CR0_MASK_DSS_ST (0x1FUL << 0) 10562306a36Sopenharmony_ci#define SSP_CR0_MASK_HALFDUP_ST (0x1UL << 5) 10662306a36Sopenharmony_ci#define SSP_CR0_MASK_CSS_ST (0x1FUL << 16) 10762306a36Sopenharmony_ci#define SSP_CR0_MASK_FRF_ST (0x3UL << 21) 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * SSP Control Register 0 - SSP_CR1 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci#define SSP_CR1_MASK_LBM (0x1UL << 0) 11362306a36Sopenharmony_ci#define SSP_CR1_MASK_SSE (0x1UL << 1) 11462306a36Sopenharmony_ci#define SSP_CR1_MASK_MS (0x1UL << 2) 11562306a36Sopenharmony_ci#define SSP_CR1_MASK_SOD (0x1UL << 3) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci/* 11862306a36Sopenharmony_ci * The ST version of this block adds some bits 11962306a36Sopenharmony_ci * in SSP_CR1 12062306a36Sopenharmony_ci */ 12162306a36Sopenharmony_ci#define SSP_CR1_MASK_RENDN_ST (0x1UL << 4) 12262306a36Sopenharmony_ci#define SSP_CR1_MASK_TENDN_ST (0x1UL << 5) 12362306a36Sopenharmony_ci#define SSP_CR1_MASK_MWAIT_ST (0x1UL << 6) 12462306a36Sopenharmony_ci#define SSP_CR1_MASK_RXIFLSEL_ST (0x7UL << 7) 12562306a36Sopenharmony_ci#define SSP_CR1_MASK_TXIFLSEL_ST (0x7UL << 10) 12662306a36Sopenharmony_ci/* This one is only in the PL023 variant */ 12762306a36Sopenharmony_ci#define SSP_CR1_MASK_FBCLKDEL_ST (0x7UL << 13) 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* 13062306a36Sopenharmony_ci * SSP Status Register - SSP_SR 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_ci#define SSP_SR_MASK_TFE (0x1UL << 0) /* Transmit FIFO empty */ 13362306a36Sopenharmony_ci#define SSP_SR_MASK_TNF (0x1UL << 1) /* Transmit FIFO not full */ 13462306a36Sopenharmony_ci#define SSP_SR_MASK_RNE (0x1UL << 2) /* Receive FIFO not empty */ 13562306a36Sopenharmony_ci#define SSP_SR_MASK_RFF (0x1UL << 3) /* Receive FIFO full */ 13662306a36Sopenharmony_ci#define SSP_SR_MASK_BSY (0x1UL << 4) /* Busy Flag */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * SSP Clock Prescale Register - SSP_CPSR 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci#define SSP_CPSR_MASK_CPSDVSR (0xFFUL << 0) 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * SSP Interrupt Mask Set/Clear Register - SSP_IMSC 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ci#define SSP_IMSC_MASK_RORIM (0x1UL << 0) /* Receive Overrun Interrupt mask */ 14762306a36Sopenharmony_ci#define SSP_IMSC_MASK_RTIM (0x1UL << 1) /* Receive timeout Interrupt mask */ 14862306a36Sopenharmony_ci#define SSP_IMSC_MASK_RXIM (0x1UL << 2) /* Receive FIFO Interrupt mask */ 14962306a36Sopenharmony_ci#define SSP_IMSC_MASK_TXIM (0x1UL << 3) /* Transmit FIFO Interrupt mask */ 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* 15262306a36Sopenharmony_ci * SSP Raw Interrupt Status Register - SSP_RIS 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci/* Receive Overrun Raw Interrupt status */ 15562306a36Sopenharmony_ci#define SSP_RIS_MASK_RORRIS (0x1UL << 0) 15662306a36Sopenharmony_ci/* Receive Timeout Raw Interrupt status */ 15762306a36Sopenharmony_ci#define SSP_RIS_MASK_RTRIS (0x1UL << 1) 15862306a36Sopenharmony_ci/* Receive FIFO Raw Interrupt status */ 15962306a36Sopenharmony_ci#define SSP_RIS_MASK_RXRIS (0x1UL << 2) 16062306a36Sopenharmony_ci/* Transmit FIFO Raw Interrupt status */ 16162306a36Sopenharmony_ci#define SSP_RIS_MASK_TXRIS (0x1UL << 3) 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* 16462306a36Sopenharmony_ci * SSP Masked Interrupt Status Register - SSP_MIS 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci/* Receive Overrun Masked Interrupt status */ 16762306a36Sopenharmony_ci#define SSP_MIS_MASK_RORMIS (0x1UL << 0) 16862306a36Sopenharmony_ci/* Receive Timeout Masked Interrupt status */ 16962306a36Sopenharmony_ci#define SSP_MIS_MASK_RTMIS (0x1UL << 1) 17062306a36Sopenharmony_ci/* Receive FIFO Masked Interrupt status */ 17162306a36Sopenharmony_ci#define SSP_MIS_MASK_RXMIS (0x1UL << 2) 17262306a36Sopenharmony_ci/* Transmit FIFO Masked Interrupt status */ 17362306a36Sopenharmony_ci#define SSP_MIS_MASK_TXMIS (0x1UL << 3) 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* 17662306a36Sopenharmony_ci * SSP Interrupt Clear Register - SSP_ICR 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci/* Receive Overrun Raw Clear Interrupt bit */ 17962306a36Sopenharmony_ci#define SSP_ICR_MASK_RORIC (0x1UL << 0) 18062306a36Sopenharmony_ci/* Receive Timeout Clear Interrupt bit */ 18162306a36Sopenharmony_ci#define SSP_ICR_MASK_RTIC (0x1UL << 1) 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci/* 18462306a36Sopenharmony_ci * SSP DMA Control Register - SSP_DMACR 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci/* Receive DMA Enable bit */ 18762306a36Sopenharmony_ci#define SSP_DMACR_MASK_RXDMAE (0x1UL << 0) 18862306a36Sopenharmony_ci/* Transmit DMA Enable bit */ 18962306a36Sopenharmony_ci#define SSP_DMACR_MASK_TXDMAE (0x1UL << 1) 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/* 19262306a36Sopenharmony_ci * SSP Chip Select Control Register - SSP_CSR 19362306a36Sopenharmony_ci * (vendor extension) 19462306a36Sopenharmony_ci */ 19562306a36Sopenharmony_ci#define SSP_CSR_CSVALUE_MASK (0x1FUL << 0) 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* 19862306a36Sopenharmony_ci * SSP Integration Test control Register - SSP_ITCR 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci#define SSP_ITCR_MASK_ITEN (0x1UL << 0) 20162306a36Sopenharmony_ci#define SSP_ITCR_MASK_TESTFIFO (0x1UL << 1) 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* 20462306a36Sopenharmony_ci * SSP Integration Test Input Register - SSP_ITIP 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci#define ITIP_MASK_SSPRXD (0x1UL << 0) 20762306a36Sopenharmony_ci#define ITIP_MASK_SSPFSSIN (0x1UL << 1) 20862306a36Sopenharmony_ci#define ITIP_MASK_SSPCLKIN (0x1UL << 2) 20962306a36Sopenharmony_ci#define ITIP_MASK_RXDMAC (0x1UL << 3) 21062306a36Sopenharmony_ci#define ITIP_MASK_TXDMAC (0x1UL << 4) 21162306a36Sopenharmony_ci#define ITIP_MASK_SSPTXDIN (0x1UL << 5) 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci/* 21462306a36Sopenharmony_ci * SSP Integration Test output Register - SSP_ITOP 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci#define ITOP_MASK_SSPTXD (0x1UL << 0) 21762306a36Sopenharmony_ci#define ITOP_MASK_SSPFSSOUT (0x1UL << 1) 21862306a36Sopenharmony_ci#define ITOP_MASK_SSPCLKOUT (0x1UL << 2) 21962306a36Sopenharmony_ci#define ITOP_MASK_SSPOEn (0x1UL << 3) 22062306a36Sopenharmony_ci#define ITOP_MASK_SSPCTLOEn (0x1UL << 4) 22162306a36Sopenharmony_ci#define ITOP_MASK_RORINTR (0x1UL << 5) 22262306a36Sopenharmony_ci#define ITOP_MASK_RTINTR (0x1UL << 6) 22362306a36Sopenharmony_ci#define ITOP_MASK_RXINTR (0x1UL << 7) 22462306a36Sopenharmony_ci#define ITOP_MASK_TXINTR (0x1UL << 8) 22562306a36Sopenharmony_ci#define ITOP_MASK_INTR (0x1UL << 9) 22662306a36Sopenharmony_ci#define ITOP_MASK_RXDMABREQ (0x1UL << 10) 22762306a36Sopenharmony_ci#define ITOP_MASK_RXDMASREQ (0x1UL << 11) 22862306a36Sopenharmony_ci#define ITOP_MASK_TXDMABREQ (0x1UL << 12) 22962306a36Sopenharmony_ci#define ITOP_MASK_TXDMASREQ (0x1UL << 13) 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* 23262306a36Sopenharmony_ci * SSP Test Data Register - SSP_TDR 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci#define TDR_MASK_TESTDATA (0xFFFFFFFF) 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* 23762306a36Sopenharmony_ci * Message State 23862306a36Sopenharmony_ci * we use the spi_message.state (void *) pointer to 23962306a36Sopenharmony_ci * hold a single state value, that's why all this 24062306a36Sopenharmony_ci * (void *) casting is done here. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ci#define STATE_START ((void *) 0) 24362306a36Sopenharmony_ci#define STATE_RUNNING ((void *) 1) 24462306a36Sopenharmony_ci#define STATE_DONE ((void *) 2) 24562306a36Sopenharmony_ci#define STATE_ERROR ((void *) -1) 24662306a36Sopenharmony_ci#define STATE_TIMEOUT ((void *) -2) 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci/* 24962306a36Sopenharmony_ci * SSP State - Whether Enabled or Disabled 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci#define SSP_DISABLED (0) 25262306a36Sopenharmony_ci#define SSP_ENABLED (1) 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 25562306a36Sopenharmony_ci * SSP DMA State - Whether DMA Enabled or Disabled 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci#define SSP_DMA_DISABLED (0) 25862306a36Sopenharmony_ci#define SSP_DMA_ENABLED (1) 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci/* 26162306a36Sopenharmony_ci * SSP Clock Defaults 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci#define SSP_DEFAULT_CLKRATE 0x2 26462306a36Sopenharmony_ci#define SSP_DEFAULT_PRESCALE 0x40 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* 26762306a36Sopenharmony_ci * SSP Clock Parameter ranges 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci#define CPSDVR_MIN 0x02 27062306a36Sopenharmony_ci#define CPSDVR_MAX 0xFE 27162306a36Sopenharmony_ci#define SCR_MIN 0x00 27262306a36Sopenharmony_ci#define SCR_MAX 0xFF 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/* 27562306a36Sopenharmony_ci * SSP Interrupt related Macros 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_ci#define DEFAULT_SSP_REG_IMSC 0x0UL 27862306a36Sopenharmony_ci#define DISABLE_ALL_INTERRUPTS DEFAULT_SSP_REG_IMSC 27962306a36Sopenharmony_ci#define ENABLE_ALL_INTERRUPTS ( \ 28062306a36Sopenharmony_ci SSP_IMSC_MASK_RORIM | \ 28162306a36Sopenharmony_ci SSP_IMSC_MASK_RTIM | \ 28262306a36Sopenharmony_ci SSP_IMSC_MASK_RXIM | \ 28362306a36Sopenharmony_ci SSP_IMSC_MASK_TXIM \ 28462306a36Sopenharmony_ci) 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci#define CLEAR_ALL_INTERRUPTS 0x3 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci#define SPI_POLLING_TIMEOUT 1000 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci/* 29162306a36Sopenharmony_ci * The type of reading going on this chip 29262306a36Sopenharmony_ci */ 29362306a36Sopenharmony_cienum ssp_reading { 29462306a36Sopenharmony_ci READING_NULL, 29562306a36Sopenharmony_ci READING_U8, 29662306a36Sopenharmony_ci READING_U16, 29762306a36Sopenharmony_ci READING_U32 29862306a36Sopenharmony_ci}; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* 30162306a36Sopenharmony_ci * The type of writing going on this chip 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_cienum ssp_writing { 30462306a36Sopenharmony_ci WRITING_NULL, 30562306a36Sopenharmony_ci WRITING_U8, 30662306a36Sopenharmony_ci WRITING_U16, 30762306a36Sopenharmony_ci WRITING_U32 30862306a36Sopenharmony_ci}; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/** 31162306a36Sopenharmony_ci * struct vendor_data - vendor-specific config parameters 31262306a36Sopenharmony_ci * for PL022 derivates 31362306a36Sopenharmony_ci * @fifodepth: depth of FIFOs (both) 31462306a36Sopenharmony_ci * @max_bpw: maximum number of bits per word 31562306a36Sopenharmony_ci * @unidir: supports unidirection transfers 31662306a36Sopenharmony_ci * @extended_cr: 32 bit wide control register 0 with extra 31762306a36Sopenharmony_ci * features and extra features in CR1 as found in the ST variants 31862306a36Sopenharmony_ci * @pl023: supports a subset of the ST extensions called "PL023" 31962306a36Sopenharmony_ci * @loopback: supports loopback mode 32062306a36Sopenharmony_ci * @internal_cs_ctrl: supports chip select control register 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_cistruct vendor_data { 32362306a36Sopenharmony_ci int fifodepth; 32462306a36Sopenharmony_ci int max_bpw; 32562306a36Sopenharmony_ci bool unidir; 32662306a36Sopenharmony_ci bool extended_cr; 32762306a36Sopenharmony_ci bool pl023; 32862306a36Sopenharmony_ci bool loopback; 32962306a36Sopenharmony_ci bool internal_cs_ctrl; 33062306a36Sopenharmony_ci}; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/** 33362306a36Sopenharmony_ci * struct pl022 - This is the private SSP driver data structure 33462306a36Sopenharmony_ci * @adev: AMBA device model hookup 33562306a36Sopenharmony_ci * @vendor: vendor data for the IP block 33662306a36Sopenharmony_ci * @phybase: the physical memory where the SSP device resides 33762306a36Sopenharmony_ci * @virtbase: the virtual memory where the SSP is mapped 33862306a36Sopenharmony_ci * @clk: outgoing clock "SPICLK" for the SPI bus 33962306a36Sopenharmony_ci * @host: SPI framework hookup 34062306a36Sopenharmony_ci * @host_info: controller-specific data from machine setup 34162306a36Sopenharmony_ci * @pump_transfers: Tasklet used in Interrupt Transfer mode 34262306a36Sopenharmony_ci * @cur_msg: Pointer to current spi_message being processed 34362306a36Sopenharmony_ci * @cur_transfer: Pointer to current spi_transfer 34462306a36Sopenharmony_ci * @cur_chip: pointer to current clients chip(assigned from controller_state) 34562306a36Sopenharmony_ci * @next_msg_cs_active: the next message in the queue has been examined 34662306a36Sopenharmony_ci * and it was found that it uses the same chip select as the previous 34762306a36Sopenharmony_ci * message, so we left it active after the previous transfer, and it's 34862306a36Sopenharmony_ci * active already. 34962306a36Sopenharmony_ci * @tx: current position in TX buffer to be read 35062306a36Sopenharmony_ci * @tx_end: end position in TX buffer to be read 35162306a36Sopenharmony_ci * @rx: current position in RX buffer to be written 35262306a36Sopenharmony_ci * @rx_end: end position in RX buffer to be written 35362306a36Sopenharmony_ci * @read: the type of read currently going on 35462306a36Sopenharmony_ci * @write: the type of write currently going on 35562306a36Sopenharmony_ci * @exp_fifo_level: expected FIFO level 35662306a36Sopenharmony_ci * @rx_lev_trig: receive FIFO watermark level which triggers IRQ 35762306a36Sopenharmony_ci * @tx_lev_trig: transmit FIFO watermark level which triggers IRQ 35862306a36Sopenharmony_ci * @dma_rx_channel: optional channel for RX DMA 35962306a36Sopenharmony_ci * @dma_tx_channel: optional channel for TX DMA 36062306a36Sopenharmony_ci * @sgt_rx: scattertable for the RX transfer 36162306a36Sopenharmony_ci * @sgt_tx: scattertable for the TX transfer 36262306a36Sopenharmony_ci * @dummypage: a dummy page used for driving data on the bus with DMA 36362306a36Sopenharmony_ci * @dma_running: indicates whether DMA is in operation 36462306a36Sopenharmony_ci * @cur_cs: current chip select index 36562306a36Sopenharmony_ci * @cur_gpiod: current chip select GPIO descriptor 36662306a36Sopenharmony_ci */ 36762306a36Sopenharmony_cistruct pl022 { 36862306a36Sopenharmony_ci struct amba_device *adev; 36962306a36Sopenharmony_ci struct vendor_data *vendor; 37062306a36Sopenharmony_ci resource_size_t phybase; 37162306a36Sopenharmony_ci void __iomem *virtbase; 37262306a36Sopenharmony_ci struct clk *clk; 37362306a36Sopenharmony_ci struct spi_controller *host; 37462306a36Sopenharmony_ci struct pl022_ssp_controller *host_info; 37562306a36Sopenharmony_ci /* Message per-transfer pump */ 37662306a36Sopenharmony_ci struct tasklet_struct pump_transfers; 37762306a36Sopenharmony_ci struct spi_message *cur_msg; 37862306a36Sopenharmony_ci struct spi_transfer *cur_transfer; 37962306a36Sopenharmony_ci struct chip_data *cur_chip; 38062306a36Sopenharmony_ci bool next_msg_cs_active; 38162306a36Sopenharmony_ci void *tx; 38262306a36Sopenharmony_ci void *tx_end; 38362306a36Sopenharmony_ci void *rx; 38462306a36Sopenharmony_ci void *rx_end; 38562306a36Sopenharmony_ci enum ssp_reading read; 38662306a36Sopenharmony_ci enum ssp_writing write; 38762306a36Sopenharmony_ci u32 exp_fifo_level; 38862306a36Sopenharmony_ci enum ssp_rx_level_trig rx_lev_trig; 38962306a36Sopenharmony_ci enum ssp_tx_level_trig tx_lev_trig; 39062306a36Sopenharmony_ci /* DMA settings */ 39162306a36Sopenharmony_ci#ifdef CONFIG_DMA_ENGINE 39262306a36Sopenharmony_ci struct dma_chan *dma_rx_channel; 39362306a36Sopenharmony_ci struct dma_chan *dma_tx_channel; 39462306a36Sopenharmony_ci struct sg_table sgt_rx; 39562306a36Sopenharmony_ci struct sg_table sgt_tx; 39662306a36Sopenharmony_ci char *dummypage; 39762306a36Sopenharmony_ci bool dma_running; 39862306a36Sopenharmony_ci#endif 39962306a36Sopenharmony_ci int cur_cs; 40062306a36Sopenharmony_ci struct gpio_desc *cur_gpiod; 40162306a36Sopenharmony_ci}; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci/** 40462306a36Sopenharmony_ci * struct chip_data - To maintain runtime state of SSP for each client chip 40562306a36Sopenharmony_ci * @cr0: Value of control register CR0 of SSP - on later ST variants this 40662306a36Sopenharmony_ci * register is 32 bits wide rather than just 16 40762306a36Sopenharmony_ci * @cr1: Value of control register CR1 of SSP 40862306a36Sopenharmony_ci * @dmacr: Value of DMA control Register of SSP 40962306a36Sopenharmony_ci * @cpsr: Value of Clock prescale register 41062306a36Sopenharmony_ci * @n_bytes: how many bytes(power of 2) reqd for a given data width of client 41162306a36Sopenharmony_ci * @enable_dma: Whether to enable DMA or not 41262306a36Sopenharmony_ci * @read: function ptr to be used to read when doing xfer for this chip 41362306a36Sopenharmony_ci * @write: function ptr to be used to write when doing xfer for this chip 41462306a36Sopenharmony_ci * @xfer_type: polling/interrupt/DMA 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * Runtime state of the SSP controller, maintained per chip, 41762306a36Sopenharmony_ci * This would be set according to the current message that would be served 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_cistruct chip_data { 42062306a36Sopenharmony_ci u32 cr0; 42162306a36Sopenharmony_ci u16 cr1; 42262306a36Sopenharmony_ci u16 dmacr; 42362306a36Sopenharmony_ci u16 cpsr; 42462306a36Sopenharmony_ci u8 n_bytes; 42562306a36Sopenharmony_ci bool enable_dma; 42662306a36Sopenharmony_ci enum ssp_reading read; 42762306a36Sopenharmony_ci enum ssp_writing write; 42862306a36Sopenharmony_ci int xfer_type; 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci/** 43262306a36Sopenharmony_ci * internal_cs_control - Control chip select signals via SSP_CSR. 43362306a36Sopenharmony_ci * @pl022: SSP driver private data structure 43462306a36Sopenharmony_ci * @command: select/delect the chip 43562306a36Sopenharmony_ci * 43662306a36Sopenharmony_ci * Used on controller with internal chip select control via SSP_CSR register 43762306a36Sopenharmony_ci * (vendor extension). Each of the 5 LSB in the register controls one chip 43862306a36Sopenharmony_ci * select signal. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_cistatic void internal_cs_control(struct pl022 *pl022, u32 command) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci u32 tmp; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci tmp = readw(SSP_CSR(pl022->virtbase)); 44562306a36Sopenharmony_ci if (command == SSP_CHIP_SELECT) 44662306a36Sopenharmony_ci tmp &= ~BIT(pl022->cur_cs); 44762306a36Sopenharmony_ci else 44862306a36Sopenharmony_ci tmp |= BIT(pl022->cur_cs); 44962306a36Sopenharmony_ci writew(tmp, SSP_CSR(pl022->virtbase)); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_cistatic void pl022_cs_control(struct pl022 *pl022, u32 command) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci if (pl022->vendor->internal_cs_ctrl) 45562306a36Sopenharmony_ci internal_cs_control(pl022, command); 45662306a36Sopenharmony_ci else if (pl022->cur_gpiod) 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * This needs to be inverted since with GPIOLIB in 45962306a36Sopenharmony_ci * control, the inversion will be handled by 46062306a36Sopenharmony_ci * GPIOLIB's active low handling. The "command" 46162306a36Sopenharmony_ci * passed into this function will be SSP_CHIP_SELECT 46262306a36Sopenharmony_ci * which is enum:ed to 0, so we need the inverse 46362306a36Sopenharmony_ci * (1) to activate chip select. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci gpiod_set_value(pl022->cur_gpiod, !command); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/** 46962306a36Sopenharmony_ci * giveback - current spi_message is over, schedule next message and call 47062306a36Sopenharmony_ci * callback of this message. Assumes that caller already 47162306a36Sopenharmony_ci * set message->status; dma and pio irqs are blocked 47262306a36Sopenharmony_ci * @pl022: SSP driver private data structure 47362306a36Sopenharmony_ci */ 47462306a36Sopenharmony_cistatic void giveback(struct pl022 *pl022) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct spi_transfer *last_transfer; 47762306a36Sopenharmony_ci pl022->next_msg_cs_active = false; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci last_transfer = list_last_entry(&pl022->cur_msg->transfers, 48062306a36Sopenharmony_ci struct spi_transfer, transfer_list); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Delay if requested before any change in chip select */ 48362306a36Sopenharmony_ci /* 48462306a36Sopenharmony_ci * FIXME: This runs in interrupt context. 48562306a36Sopenharmony_ci * Is this really smart? 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci spi_transfer_delay_exec(last_transfer); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (!last_transfer->cs_change) { 49062306a36Sopenharmony_ci struct spi_message *next_msg; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* 49362306a36Sopenharmony_ci * cs_change was not set. We can keep the chip select 49462306a36Sopenharmony_ci * enabled if there is message in the queue and it is 49562306a36Sopenharmony_ci * for the same spi device. 49662306a36Sopenharmony_ci * 49762306a36Sopenharmony_ci * We cannot postpone this until pump_messages, because 49862306a36Sopenharmony_ci * after calling msg->complete (below) the driver that 49962306a36Sopenharmony_ci * sent the current message could be unloaded, which 50062306a36Sopenharmony_ci * could invalidate the cs_control() callback... 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci /* get a pointer to the next message, if any */ 50362306a36Sopenharmony_ci next_msg = spi_get_next_queued_message(pl022->host); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * see if the next and current messages point 50762306a36Sopenharmony_ci * to the same spi device. 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_ci if (next_msg && next_msg->spi != pl022->cur_msg->spi) 51062306a36Sopenharmony_ci next_msg = NULL; 51162306a36Sopenharmony_ci if (!next_msg || pl022->cur_msg->state == STATE_ERROR) 51262306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 51362306a36Sopenharmony_ci else 51462306a36Sopenharmony_ci pl022->next_msg_cs_active = true; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci pl022->cur_msg = NULL; 51962306a36Sopenharmony_ci pl022->cur_transfer = NULL; 52062306a36Sopenharmony_ci pl022->cur_chip = NULL; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* disable the SPI/SSP operation */ 52362306a36Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & 52462306a36Sopenharmony_ci (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci spi_finalize_current_message(pl022->host); 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci/** 53062306a36Sopenharmony_ci * flush - flush the FIFO to reach a clean state 53162306a36Sopenharmony_ci * @pl022: SSP driver private data structure 53262306a36Sopenharmony_ci */ 53362306a36Sopenharmony_cistatic int flush(struct pl022 *pl022) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci unsigned long limit = loops_per_jiffy << 1; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "flush\n"); 53862306a36Sopenharmony_ci do { 53962306a36Sopenharmony_ci while (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) 54062306a36Sopenharmony_ci readw(SSP_DR(pl022->virtbase)); 54162306a36Sopenharmony_ci } while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_BSY) && limit--); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci pl022->exp_fifo_level = 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return limit; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci/** 54962306a36Sopenharmony_ci * restore_state - Load configuration of current chip 55062306a36Sopenharmony_ci * @pl022: SSP driver private data structure 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_cistatic void restore_state(struct pl022 *pl022) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct chip_data *chip = pl022->cur_chip; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (pl022->vendor->extended_cr) 55762306a36Sopenharmony_ci writel(chip->cr0, SSP_CR0(pl022->virtbase)); 55862306a36Sopenharmony_ci else 55962306a36Sopenharmony_ci writew(chip->cr0, SSP_CR0(pl022->virtbase)); 56062306a36Sopenharmony_ci writew(chip->cr1, SSP_CR1(pl022->virtbase)); 56162306a36Sopenharmony_ci writew(chip->dmacr, SSP_DMACR(pl022->virtbase)); 56262306a36Sopenharmony_ci writew(chip->cpsr, SSP_CPSR(pl022->virtbase)); 56362306a36Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); 56462306a36Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/* 56862306a36Sopenharmony_ci * Default SSP Register Values 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_ci#define DEFAULT_SSP_REG_CR0 ( \ 57162306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS, 0) | \ 57262306a36Sopenharmony_ci GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF, 4) | \ 57362306a36Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ 57462306a36Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ 57562306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \ 57662306a36Sopenharmony_ci) 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/* ST versions have slightly different bit layout */ 57962306a36Sopenharmony_ci#define DEFAULT_SSP_REG_CR0_ST ( \ 58062306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \ 58162306a36Sopenharmony_ci GEN_MASK_BITS(SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, SSP_CR0_MASK_HALFDUP_ST, 5) | \ 58262306a36Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ 58362306a36Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ 58462306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) | \ 58562306a36Sopenharmony_ci GEN_MASK_BITS(SSP_BITS_8, SSP_CR0_MASK_CSS_ST, 16) | \ 58662306a36Sopenharmony_ci GEN_MASK_BITS(SSP_INTERFACE_MOTOROLA_SPI, SSP_CR0_MASK_FRF_ST, 21) \ 58762306a36Sopenharmony_ci) 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/* The PL023 version is slightly different again */ 59062306a36Sopenharmony_ci#define DEFAULT_SSP_REG_CR0_ST_PL023 ( \ 59162306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DATA_BITS_12, SSP_CR0_MASK_DSS_ST, 0) | \ 59262306a36Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_POL_IDLE_LOW, SSP_CR0_MASK_SPO, 6) | \ 59362306a36Sopenharmony_ci GEN_MASK_BITS(SSP_CLK_SECOND_EDGE, SSP_CR0_MASK_SPH, 7) | \ 59462306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_CLKRATE, SSP_CR0_MASK_SCR, 8) \ 59562306a36Sopenharmony_ci) 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci#define DEFAULT_SSP_REG_CR1 ( \ 59862306a36Sopenharmony_ci GEN_MASK_BITS(LOOPBACK_DISABLED, SSP_CR1_MASK_LBM, 0) | \ 59962306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \ 60062306a36Sopenharmony_ci GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \ 60162306a36Sopenharmony_ci GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) \ 60262306a36Sopenharmony_ci) 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci/* ST versions extend this register to use all 16 bits */ 60562306a36Sopenharmony_ci#define DEFAULT_SSP_REG_CR1_ST ( \ 60662306a36Sopenharmony_ci DEFAULT_SSP_REG_CR1 | \ 60762306a36Sopenharmony_ci GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \ 60862306a36Sopenharmony_ci GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \ 60962306a36Sopenharmony_ci GEN_MASK_BITS(SSP_MWIRE_WAIT_ZERO, SSP_CR1_MASK_MWAIT_ST, 6) |\ 61062306a36Sopenharmony_ci GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \ 61162306a36Sopenharmony_ci GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) \ 61262306a36Sopenharmony_ci) 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci/* 61562306a36Sopenharmony_ci * The PL023 variant has further differences: no loopback mode, no microwire 61662306a36Sopenharmony_ci * support, and a new clock feedback delay setting. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_ci#define DEFAULT_SSP_REG_CR1_ST_PL023 ( \ 61962306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DISABLED, SSP_CR1_MASK_SSE, 1) | \ 62062306a36Sopenharmony_ci GEN_MASK_BITS(SSP_MASTER, SSP_CR1_MASK_MS, 2) | \ 62162306a36Sopenharmony_ci GEN_MASK_BITS(DO_NOT_DRIVE_TX, SSP_CR1_MASK_SOD, 3) | \ 62262306a36Sopenharmony_ci GEN_MASK_BITS(SSP_RX_MSB, SSP_CR1_MASK_RENDN_ST, 4) | \ 62362306a36Sopenharmony_ci GEN_MASK_BITS(SSP_TX_MSB, SSP_CR1_MASK_TENDN_ST, 5) | \ 62462306a36Sopenharmony_ci GEN_MASK_BITS(SSP_RX_1_OR_MORE_ELEM, SSP_CR1_MASK_RXIFLSEL_ST, 7) | \ 62562306a36Sopenharmony_ci GEN_MASK_BITS(SSP_TX_1_OR_MORE_EMPTY_LOC, SSP_CR1_MASK_TXIFLSEL_ST, 10) | \ 62662306a36Sopenharmony_ci GEN_MASK_BITS(SSP_FEEDBACK_CLK_DELAY_NONE, SSP_CR1_MASK_FBCLKDEL_ST, 13) \ 62762306a36Sopenharmony_ci) 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci#define DEFAULT_SSP_REG_CPSR ( \ 63062306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DEFAULT_PRESCALE, SSP_CPSR_MASK_CPSDVSR, 0) \ 63162306a36Sopenharmony_ci) 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci#define DEFAULT_SSP_REG_DMACR (\ 63462306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_RXDMAE, 0) | \ 63562306a36Sopenharmony_ci GEN_MASK_BITS(SSP_DMA_DISABLED, SSP_DMACR_MASK_TXDMAE, 1) \ 63662306a36Sopenharmony_ci) 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci/** 63962306a36Sopenharmony_ci * load_ssp_default_config - Load default configuration for SSP 64062306a36Sopenharmony_ci * @pl022: SSP driver private data structure 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_cistatic void load_ssp_default_config(struct pl022 *pl022) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci if (pl022->vendor->pl023) { 64562306a36Sopenharmony_ci writel(DEFAULT_SSP_REG_CR0_ST_PL023, SSP_CR0(pl022->virtbase)); 64662306a36Sopenharmony_ci writew(DEFAULT_SSP_REG_CR1_ST_PL023, SSP_CR1(pl022->virtbase)); 64762306a36Sopenharmony_ci } else if (pl022->vendor->extended_cr) { 64862306a36Sopenharmony_ci writel(DEFAULT_SSP_REG_CR0_ST, SSP_CR0(pl022->virtbase)); 64962306a36Sopenharmony_ci writew(DEFAULT_SSP_REG_CR1_ST, SSP_CR1(pl022->virtbase)); 65062306a36Sopenharmony_ci } else { 65162306a36Sopenharmony_ci writew(DEFAULT_SSP_REG_CR0, SSP_CR0(pl022->virtbase)); 65262306a36Sopenharmony_ci writew(DEFAULT_SSP_REG_CR1, SSP_CR1(pl022->virtbase)); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci writew(DEFAULT_SSP_REG_DMACR, SSP_DMACR(pl022->virtbase)); 65562306a36Sopenharmony_ci writew(DEFAULT_SSP_REG_CPSR, SSP_CPSR(pl022->virtbase)); 65662306a36Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, SSP_IMSC(pl022->virtbase)); 65762306a36Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci/* 66162306a36Sopenharmony_ci * This will write to TX and read from RX according to the parameters 66262306a36Sopenharmony_ci * set in pl022. 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_cistatic void readwriter(struct pl022 *pl022) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * The FIFO depth is different between primecell variants. 66962306a36Sopenharmony_ci * I believe filling in too much in the FIFO might cause 67062306a36Sopenharmony_ci * errons in 8bit wide transfers on ARM variants (just 8 words 67162306a36Sopenharmony_ci * FIFO, means only 8x8 = 64 bits in FIFO) at least. 67262306a36Sopenharmony_ci * 67362306a36Sopenharmony_ci * To prevent this issue, the TX FIFO is only filled to the 67462306a36Sopenharmony_ci * unused RX FIFO fill length, regardless of what the TX 67562306a36Sopenharmony_ci * FIFO status flag indicates. 67662306a36Sopenharmony_ci */ 67762306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, 67862306a36Sopenharmony_ci "%s, rx: %p, rxend: %p, tx: %p, txend: %p\n", 67962306a36Sopenharmony_ci __func__, pl022->rx, pl022->rx_end, pl022->tx, pl022->tx_end); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* Read as much as you can */ 68262306a36Sopenharmony_ci while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) 68362306a36Sopenharmony_ci && (pl022->rx < pl022->rx_end)) { 68462306a36Sopenharmony_ci switch (pl022->read) { 68562306a36Sopenharmony_ci case READING_NULL: 68662306a36Sopenharmony_ci readw(SSP_DR(pl022->virtbase)); 68762306a36Sopenharmony_ci break; 68862306a36Sopenharmony_ci case READING_U8: 68962306a36Sopenharmony_ci *(u8 *) (pl022->rx) = 69062306a36Sopenharmony_ci readw(SSP_DR(pl022->virtbase)) & 0xFFU; 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci case READING_U16: 69362306a36Sopenharmony_ci *(u16 *) (pl022->rx) = 69462306a36Sopenharmony_ci (u16) readw(SSP_DR(pl022->virtbase)); 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci case READING_U32: 69762306a36Sopenharmony_ci *(u32 *) (pl022->rx) = 69862306a36Sopenharmony_ci readl(SSP_DR(pl022->virtbase)); 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci pl022->rx += (pl022->cur_chip->n_bytes); 70262306a36Sopenharmony_ci pl022->exp_fifo_level--; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci /* 70562306a36Sopenharmony_ci * Write as much as possible up to the RX FIFO size 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci while ((pl022->exp_fifo_level < pl022->vendor->fifodepth) 70862306a36Sopenharmony_ci && (pl022->tx < pl022->tx_end)) { 70962306a36Sopenharmony_ci switch (pl022->write) { 71062306a36Sopenharmony_ci case WRITING_NULL: 71162306a36Sopenharmony_ci writew(0x0, SSP_DR(pl022->virtbase)); 71262306a36Sopenharmony_ci break; 71362306a36Sopenharmony_ci case WRITING_U8: 71462306a36Sopenharmony_ci writew(*(u8 *) (pl022->tx), SSP_DR(pl022->virtbase)); 71562306a36Sopenharmony_ci break; 71662306a36Sopenharmony_ci case WRITING_U16: 71762306a36Sopenharmony_ci writew((*(u16 *) (pl022->tx)), SSP_DR(pl022->virtbase)); 71862306a36Sopenharmony_ci break; 71962306a36Sopenharmony_ci case WRITING_U32: 72062306a36Sopenharmony_ci writel(*(u32 *) (pl022->tx), SSP_DR(pl022->virtbase)); 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci pl022->tx += (pl022->cur_chip->n_bytes); 72462306a36Sopenharmony_ci pl022->exp_fifo_level++; 72562306a36Sopenharmony_ci /* 72662306a36Sopenharmony_ci * This inner reader takes care of things appearing in the RX 72762306a36Sopenharmony_ci * FIFO as we're transmitting. This will happen a lot since the 72862306a36Sopenharmony_ci * clock starts running when you put things into the TX FIFO, 72962306a36Sopenharmony_ci * and then things are continuously clocked into the RX FIFO. 73062306a36Sopenharmony_ci */ 73162306a36Sopenharmony_ci while ((readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RNE) 73262306a36Sopenharmony_ci && (pl022->rx < pl022->rx_end)) { 73362306a36Sopenharmony_ci switch (pl022->read) { 73462306a36Sopenharmony_ci case READING_NULL: 73562306a36Sopenharmony_ci readw(SSP_DR(pl022->virtbase)); 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci case READING_U8: 73862306a36Sopenharmony_ci *(u8 *) (pl022->rx) = 73962306a36Sopenharmony_ci readw(SSP_DR(pl022->virtbase)) & 0xFFU; 74062306a36Sopenharmony_ci break; 74162306a36Sopenharmony_ci case READING_U16: 74262306a36Sopenharmony_ci *(u16 *) (pl022->rx) = 74362306a36Sopenharmony_ci (u16) readw(SSP_DR(pl022->virtbase)); 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case READING_U32: 74662306a36Sopenharmony_ci *(u32 *) (pl022->rx) = 74762306a36Sopenharmony_ci readl(SSP_DR(pl022->virtbase)); 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci pl022->rx += (pl022->cur_chip->n_bytes); 75162306a36Sopenharmony_ci pl022->exp_fifo_level--; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci /* 75562306a36Sopenharmony_ci * When we exit here the TX FIFO should be full and the RX FIFO 75662306a36Sopenharmony_ci * should be empty 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci/** 76162306a36Sopenharmony_ci * next_transfer - Move to the Next transfer in the current spi message 76262306a36Sopenharmony_ci * @pl022: SSP driver private data structure 76362306a36Sopenharmony_ci * 76462306a36Sopenharmony_ci * This function moves though the linked list of spi transfers in the 76562306a36Sopenharmony_ci * current spi message and returns with the state of current spi 76662306a36Sopenharmony_ci * message i.e whether its last transfer is done(STATE_DONE) or 76762306a36Sopenharmony_ci * Next transfer is ready(STATE_RUNNING) 76862306a36Sopenharmony_ci */ 76962306a36Sopenharmony_cistatic void *next_transfer(struct pl022 *pl022) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct spi_message *msg = pl022->cur_msg; 77262306a36Sopenharmony_ci struct spi_transfer *trans = pl022->cur_transfer; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci /* Move to next transfer */ 77562306a36Sopenharmony_ci if (trans->transfer_list.next != &msg->transfers) { 77662306a36Sopenharmony_ci pl022->cur_transfer = 77762306a36Sopenharmony_ci list_entry(trans->transfer_list.next, 77862306a36Sopenharmony_ci struct spi_transfer, transfer_list); 77962306a36Sopenharmony_ci return STATE_RUNNING; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci return STATE_DONE; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci/* 78562306a36Sopenharmony_ci * This DMA functionality is only compiled in if we have 78662306a36Sopenharmony_ci * access to the generic DMA devices/DMA engine. 78762306a36Sopenharmony_ci */ 78862306a36Sopenharmony_ci#ifdef CONFIG_DMA_ENGINE 78962306a36Sopenharmony_cistatic void unmap_free_dma_scatter(struct pl022 *pl022) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci /* Unmap and free the SG tables */ 79262306a36Sopenharmony_ci dma_unmap_sg(pl022->dma_tx_channel->device->dev, pl022->sgt_tx.sgl, 79362306a36Sopenharmony_ci pl022->sgt_tx.nents, DMA_TO_DEVICE); 79462306a36Sopenharmony_ci dma_unmap_sg(pl022->dma_rx_channel->device->dev, pl022->sgt_rx.sgl, 79562306a36Sopenharmony_ci pl022->sgt_rx.nents, DMA_FROM_DEVICE); 79662306a36Sopenharmony_ci sg_free_table(&pl022->sgt_rx); 79762306a36Sopenharmony_ci sg_free_table(&pl022->sgt_tx); 79862306a36Sopenharmony_ci} 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_cistatic void dma_callback(void *data) 80162306a36Sopenharmony_ci{ 80262306a36Sopenharmony_ci struct pl022 *pl022 = data; 80362306a36Sopenharmony_ci struct spi_message *msg = pl022->cur_msg; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci BUG_ON(!pl022->sgt_rx.sgl); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci#ifdef VERBOSE_DEBUG 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci * Optionally dump out buffers to inspect contents, this is 81062306a36Sopenharmony_ci * good if you want to convince yourself that the loopback 81162306a36Sopenharmony_ci * read/write contents are the same, when adopting to a new 81262306a36Sopenharmony_ci * DMA engine. 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_ci { 81562306a36Sopenharmony_ci struct scatterlist *sg; 81662306a36Sopenharmony_ci unsigned int i; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci dma_sync_sg_for_cpu(&pl022->adev->dev, 81962306a36Sopenharmony_ci pl022->sgt_rx.sgl, 82062306a36Sopenharmony_ci pl022->sgt_rx.nents, 82162306a36Sopenharmony_ci DMA_FROM_DEVICE); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci for_each_sg(pl022->sgt_rx.sgl, sg, pl022->sgt_rx.nents, i) { 82462306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "SPI RX SG ENTRY: %d", i); 82562306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "SPI RX: ", 82662306a36Sopenharmony_ci DUMP_PREFIX_OFFSET, 82762306a36Sopenharmony_ci 16, 82862306a36Sopenharmony_ci 1, 82962306a36Sopenharmony_ci sg_virt(sg), 83062306a36Sopenharmony_ci sg_dma_len(sg), 83162306a36Sopenharmony_ci 1); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci for_each_sg(pl022->sgt_tx.sgl, sg, pl022->sgt_tx.nents, i) { 83462306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "SPI TX SG ENTRY: %d", i); 83562306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "SPI TX: ", 83662306a36Sopenharmony_ci DUMP_PREFIX_OFFSET, 83762306a36Sopenharmony_ci 16, 83862306a36Sopenharmony_ci 1, 83962306a36Sopenharmony_ci sg_virt(sg), 84062306a36Sopenharmony_ci sg_dma_len(sg), 84162306a36Sopenharmony_ci 1); 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci#endif 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci unmap_free_dma_scatter(pl022); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* Update total bytes transferred */ 84962306a36Sopenharmony_ci msg->actual_length += pl022->cur_transfer->len; 85062306a36Sopenharmony_ci /* Move to next transfer */ 85162306a36Sopenharmony_ci msg->state = next_transfer(pl022); 85262306a36Sopenharmony_ci if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change) 85362306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 85462306a36Sopenharmony_ci tasklet_schedule(&pl022->pump_transfers); 85562306a36Sopenharmony_ci} 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_cistatic void setup_dma_scatter(struct pl022 *pl022, 85862306a36Sopenharmony_ci void *buffer, 85962306a36Sopenharmony_ci unsigned int length, 86062306a36Sopenharmony_ci struct sg_table *sgtab) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct scatterlist *sg; 86362306a36Sopenharmony_ci int bytesleft = length; 86462306a36Sopenharmony_ci void *bufp = buffer; 86562306a36Sopenharmony_ci int mapbytes; 86662306a36Sopenharmony_ci int i; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (buffer) { 86962306a36Sopenharmony_ci for_each_sg(sgtab->sgl, sg, sgtab->nents, i) { 87062306a36Sopenharmony_ci /* 87162306a36Sopenharmony_ci * If there are less bytes left than what fits 87262306a36Sopenharmony_ci * in the current page (plus page alignment offset) 87362306a36Sopenharmony_ci * we just feed in this, else we stuff in as much 87462306a36Sopenharmony_ci * as we can. 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci if (bytesleft < (PAGE_SIZE - offset_in_page(bufp))) 87762306a36Sopenharmony_ci mapbytes = bytesleft; 87862306a36Sopenharmony_ci else 87962306a36Sopenharmony_ci mapbytes = PAGE_SIZE - offset_in_page(bufp); 88062306a36Sopenharmony_ci sg_set_page(sg, virt_to_page(bufp), 88162306a36Sopenharmony_ci mapbytes, offset_in_page(bufp)); 88262306a36Sopenharmony_ci bufp += mapbytes; 88362306a36Sopenharmony_ci bytesleft -= mapbytes; 88462306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, 88562306a36Sopenharmony_ci "set RX/TX target page @ %p, %d bytes, %d left\n", 88662306a36Sopenharmony_ci bufp, mapbytes, bytesleft); 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci } else { 88962306a36Sopenharmony_ci /* Map the dummy buffer on every page */ 89062306a36Sopenharmony_ci for_each_sg(sgtab->sgl, sg, sgtab->nents, i) { 89162306a36Sopenharmony_ci if (bytesleft < PAGE_SIZE) 89262306a36Sopenharmony_ci mapbytes = bytesleft; 89362306a36Sopenharmony_ci else 89462306a36Sopenharmony_ci mapbytes = PAGE_SIZE; 89562306a36Sopenharmony_ci sg_set_page(sg, virt_to_page(pl022->dummypage), 89662306a36Sopenharmony_ci mapbytes, 0); 89762306a36Sopenharmony_ci bytesleft -= mapbytes; 89862306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, 89962306a36Sopenharmony_ci "set RX/TX to dummy page %d bytes, %d left\n", 90062306a36Sopenharmony_ci mapbytes, bytesleft); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci BUG_ON(bytesleft); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci/** 90862306a36Sopenharmony_ci * configure_dma - configures the channels for the next transfer 90962306a36Sopenharmony_ci * @pl022: SSP driver's private data structure 91062306a36Sopenharmony_ci */ 91162306a36Sopenharmony_cistatic int configure_dma(struct pl022 *pl022) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci struct dma_slave_config rx_conf = { 91462306a36Sopenharmony_ci .src_addr = SSP_DR(pl022->phybase), 91562306a36Sopenharmony_ci .direction = DMA_DEV_TO_MEM, 91662306a36Sopenharmony_ci .device_fc = false, 91762306a36Sopenharmony_ci }; 91862306a36Sopenharmony_ci struct dma_slave_config tx_conf = { 91962306a36Sopenharmony_ci .dst_addr = SSP_DR(pl022->phybase), 92062306a36Sopenharmony_ci .direction = DMA_MEM_TO_DEV, 92162306a36Sopenharmony_ci .device_fc = false, 92262306a36Sopenharmony_ci }; 92362306a36Sopenharmony_ci unsigned int pages; 92462306a36Sopenharmony_ci int ret; 92562306a36Sopenharmony_ci int rx_sglen, tx_sglen; 92662306a36Sopenharmony_ci struct dma_chan *rxchan = pl022->dma_rx_channel; 92762306a36Sopenharmony_ci struct dma_chan *txchan = pl022->dma_tx_channel; 92862306a36Sopenharmony_ci struct dma_async_tx_descriptor *rxdesc; 92962306a36Sopenharmony_ci struct dma_async_tx_descriptor *txdesc; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci /* Check that the channels are available */ 93262306a36Sopenharmony_ci if (!rxchan || !txchan) 93362306a36Sopenharmony_ci return -ENODEV; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* 93662306a36Sopenharmony_ci * If supplied, the DMA burstsize should equal the FIFO trigger level. 93762306a36Sopenharmony_ci * Notice that the DMA engine uses one-to-one mapping. Since we can 93862306a36Sopenharmony_ci * not trigger on 2 elements this needs explicit mapping rather than 93962306a36Sopenharmony_ci * calculation. 94062306a36Sopenharmony_ci */ 94162306a36Sopenharmony_ci switch (pl022->rx_lev_trig) { 94262306a36Sopenharmony_ci case SSP_RX_1_OR_MORE_ELEM: 94362306a36Sopenharmony_ci rx_conf.src_maxburst = 1; 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci case SSP_RX_4_OR_MORE_ELEM: 94662306a36Sopenharmony_ci rx_conf.src_maxburst = 4; 94762306a36Sopenharmony_ci break; 94862306a36Sopenharmony_ci case SSP_RX_8_OR_MORE_ELEM: 94962306a36Sopenharmony_ci rx_conf.src_maxburst = 8; 95062306a36Sopenharmony_ci break; 95162306a36Sopenharmony_ci case SSP_RX_16_OR_MORE_ELEM: 95262306a36Sopenharmony_ci rx_conf.src_maxburst = 16; 95362306a36Sopenharmony_ci break; 95462306a36Sopenharmony_ci case SSP_RX_32_OR_MORE_ELEM: 95562306a36Sopenharmony_ci rx_conf.src_maxburst = 32; 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci default: 95862306a36Sopenharmony_ci rx_conf.src_maxburst = pl022->vendor->fifodepth >> 1; 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci switch (pl022->tx_lev_trig) { 96362306a36Sopenharmony_ci case SSP_TX_1_OR_MORE_EMPTY_LOC: 96462306a36Sopenharmony_ci tx_conf.dst_maxburst = 1; 96562306a36Sopenharmony_ci break; 96662306a36Sopenharmony_ci case SSP_TX_4_OR_MORE_EMPTY_LOC: 96762306a36Sopenharmony_ci tx_conf.dst_maxburst = 4; 96862306a36Sopenharmony_ci break; 96962306a36Sopenharmony_ci case SSP_TX_8_OR_MORE_EMPTY_LOC: 97062306a36Sopenharmony_ci tx_conf.dst_maxburst = 8; 97162306a36Sopenharmony_ci break; 97262306a36Sopenharmony_ci case SSP_TX_16_OR_MORE_EMPTY_LOC: 97362306a36Sopenharmony_ci tx_conf.dst_maxburst = 16; 97462306a36Sopenharmony_ci break; 97562306a36Sopenharmony_ci case SSP_TX_32_OR_MORE_EMPTY_LOC: 97662306a36Sopenharmony_ci tx_conf.dst_maxburst = 32; 97762306a36Sopenharmony_ci break; 97862306a36Sopenharmony_ci default: 97962306a36Sopenharmony_ci tx_conf.dst_maxburst = pl022->vendor->fifodepth >> 1; 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci switch (pl022->read) { 98462306a36Sopenharmony_ci case READING_NULL: 98562306a36Sopenharmony_ci /* Use the same as for writing */ 98662306a36Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; 98762306a36Sopenharmony_ci break; 98862306a36Sopenharmony_ci case READING_U8: 98962306a36Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 99062306a36Sopenharmony_ci break; 99162306a36Sopenharmony_ci case READING_U16: 99262306a36Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 99362306a36Sopenharmony_ci break; 99462306a36Sopenharmony_ci case READING_U32: 99562306a36Sopenharmony_ci rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 99662306a36Sopenharmony_ci break; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci switch (pl022->write) { 100062306a36Sopenharmony_ci case WRITING_NULL: 100162306a36Sopenharmony_ci /* Use the same as for reading */ 100262306a36Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_UNDEFINED; 100362306a36Sopenharmony_ci break; 100462306a36Sopenharmony_ci case WRITING_U8: 100562306a36Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; 100662306a36Sopenharmony_ci break; 100762306a36Sopenharmony_ci case WRITING_U16: 100862306a36Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; 100962306a36Sopenharmony_ci break; 101062306a36Sopenharmony_ci case WRITING_U32: 101162306a36Sopenharmony_ci tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 101262306a36Sopenharmony_ci break; 101362306a36Sopenharmony_ci } 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci /* SPI pecularity: we need to read and write the same width */ 101662306a36Sopenharmony_ci if (rx_conf.src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) 101762306a36Sopenharmony_ci rx_conf.src_addr_width = tx_conf.dst_addr_width; 101862306a36Sopenharmony_ci if (tx_conf.dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) 101962306a36Sopenharmony_ci tx_conf.dst_addr_width = rx_conf.src_addr_width; 102062306a36Sopenharmony_ci BUG_ON(rx_conf.src_addr_width != tx_conf.dst_addr_width); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci dmaengine_slave_config(rxchan, &rx_conf); 102362306a36Sopenharmony_ci dmaengine_slave_config(txchan, &tx_conf); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* Create sglists for the transfers */ 102662306a36Sopenharmony_ci pages = DIV_ROUND_UP(pl022->cur_transfer->len, PAGE_SIZE); 102762306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "using %d pages for transfer\n", pages); 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci ret = sg_alloc_table(&pl022->sgt_rx, pages, GFP_ATOMIC); 103062306a36Sopenharmony_ci if (ret) 103162306a36Sopenharmony_ci goto err_alloc_rx_sg; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci ret = sg_alloc_table(&pl022->sgt_tx, pages, GFP_ATOMIC); 103462306a36Sopenharmony_ci if (ret) 103562306a36Sopenharmony_ci goto err_alloc_tx_sg; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* Fill in the scatterlists for the RX+TX buffers */ 103862306a36Sopenharmony_ci setup_dma_scatter(pl022, pl022->rx, 103962306a36Sopenharmony_ci pl022->cur_transfer->len, &pl022->sgt_rx); 104062306a36Sopenharmony_ci setup_dma_scatter(pl022, pl022->tx, 104162306a36Sopenharmony_ci pl022->cur_transfer->len, &pl022->sgt_tx); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* Map DMA buffers */ 104462306a36Sopenharmony_ci rx_sglen = dma_map_sg(rxchan->device->dev, pl022->sgt_rx.sgl, 104562306a36Sopenharmony_ci pl022->sgt_rx.nents, DMA_FROM_DEVICE); 104662306a36Sopenharmony_ci if (!rx_sglen) 104762306a36Sopenharmony_ci goto err_rx_sgmap; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci tx_sglen = dma_map_sg(txchan->device->dev, pl022->sgt_tx.sgl, 105062306a36Sopenharmony_ci pl022->sgt_tx.nents, DMA_TO_DEVICE); 105162306a36Sopenharmony_ci if (!tx_sglen) 105262306a36Sopenharmony_ci goto err_tx_sgmap; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* Send both scatterlists */ 105562306a36Sopenharmony_ci rxdesc = dmaengine_prep_slave_sg(rxchan, 105662306a36Sopenharmony_ci pl022->sgt_rx.sgl, 105762306a36Sopenharmony_ci rx_sglen, 105862306a36Sopenharmony_ci DMA_DEV_TO_MEM, 105962306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 106062306a36Sopenharmony_ci if (!rxdesc) 106162306a36Sopenharmony_ci goto err_rxdesc; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci txdesc = dmaengine_prep_slave_sg(txchan, 106462306a36Sopenharmony_ci pl022->sgt_tx.sgl, 106562306a36Sopenharmony_ci tx_sglen, 106662306a36Sopenharmony_ci DMA_MEM_TO_DEV, 106762306a36Sopenharmony_ci DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 106862306a36Sopenharmony_ci if (!txdesc) 106962306a36Sopenharmony_ci goto err_txdesc; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci /* Put the callback on the RX transfer only, that should finish last */ 107262306a36Sopenharmony_ci rxdesc->callback = dma_callback; 107362306a36Sopenharmony_ci rxdesc->callback_param = pl022; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* Submit and fire RX and TX with TX last so we're ready to read! */ 107662306a36Sopenharmony_ci dmaengine_submit(rxdesc); 107762306a36Sopenharmony_ci dmaengine_submit(txdesc); 107862306a36Sopenharmony_ci dma_async_issue_pending(rxchan); 107962306a36Sopenharmony_ci dma_async_issue_pending(txchan); 108062306a36Sopenharmony_ci pl022->dma_running = true; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci return 0; 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cierr_txdesc: 108562306a36Sopenharmony_ci dmaengine_terminate_all(txchan); 108662306a36Sopenharmony_cierr_rxdesc: 108762306a36Sopenharmony_ci dmaengine_terminate_all(rxchan); 108862306a36Sopenharmony_ci dma_unmap_sg(txchan->device->dev, pl022->sgt_tx.sgl, 108962306a36Sopenharmony_ci pl022->sgt_tx.nents, DMA_TO_DEVICE); 109062306a36Sopenharmony_cierr_tx_sgmap: 109162306a36Sopenharmony_ci dma_unmap_sg(rxchan->device->dev, pl022->sgt_rx.sgl, 109262306a36Sopenharmony_ci pl022->sgt_rx.nents, DMA_FROM_DEVICE); 109362306a36Sopenharmony_cierr_rx_sgmap: 109462306a36Sopenharmony_ci sg_free_table(&pl022->sgt_tx); 109562306a36Sopenharmony_cierr_alloc_tx_sg: 109662306a36Sopenharmony_ci sg_free_table(&pl022->sgt_rx); 109762306a36Sopenharmony_cierr_alloc_rx_sg: 109862306a36Sopenharmony_ci return -ENOMEM; 109962306a36Sopenharmony_ci} 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_cistatic int pl022_dma_probe(struct pl022 *pl022) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci dma_cap_mask_t mask; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci /* Try to acquire a generic DMA engine slave channel */ 110662306a36Sopenharmony_ci dma_cap_zero(mask); 110762306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 110862306a36Sopenharmony_ci /* 110962306a36Sopenharmony_ci * We need both RX and TX channels to do DMA, else do none 111062306a36Sopenharmony_ci * of them. 111162306a36Sopenharmony_ci */ 111262306a36Sopenharmony_ci pl022->dma_rx_channel = dma_request_channel(mask, 111362306a36Sopenharmony_ci pl022->host_info->dma_filter, 111462306a36Sopenharmony_ci pl022->host_info->dma_rx_param); 111562306a36Sopenharmony_ci if (!pl022->dma_rx_channel) { 111662306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "no RX DMA channel!\n"); 111762306a36Sopenharmony_ci goto err_no_rxchan; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci pl022->dma_tx_channel = dma_request_channel(mask, 112162306a36Sopenharmony_ci pl022->host_info->dma_filter, 112262306a36Sopenharmony_ci pl022->host_info->dma_tx_param); 112362306a36Sopenharmony_ci if (!pl022->dma_tx_channel) { 112462306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "no TX DMA channel!\n"); 112562306a36Sopenharmony_ci goto err_no_txchan; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); 112962306a36Sopenharmony_ci if (!pl022->dummypage) 113062306a36Sopenharmony_ci goto err_no_dummypage; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci dev_info(&pl022->adev->dev, "setup for DMA on RX %s, TX %s\n", 113362306a36Sopenharmony_ci dma_chan_name(pl022->dma_rx_channel), 113462306a36Sopenharmony_ci dma_chan_name(pl022->dma_tx_channel)); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci return 0; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_cierr_no_dummypage: 113962306a36Sopenharmony_ci dma_release_channel(pl022->dma_tx_channel); 114062306a36Sopenharmony_cierr_no_txchan: 114162306a36Sopenharmony_ci dma_release_channel(pl022->dma_rx_channel); 114262306a36Sopenharmony_ci pl022->dma_rx_channel = NULL; 114362306a36Sopenharmony_cierr_no_rxchan: 114462306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 114562306a36Sopenharmony_ci "Failed to work in dma mode, work without dma!\n"); 114662306a36Sopenharmony_ci return -ENODEV; 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_cistatic int pl022_dma_autoprobe(struct pl022 *pl022) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct device *dev = &pl022->adev->dev; 115262306a36Sopenharmony_ci struct dma_chan *chan; 115362306a36Sopenharmony_ci int err; 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* automatically configure DMA channels from platform, normally using DT */ 115662306a36Sopenharmony_ci chan = dma_request_chan(dev, "rx"); 115762306a36Sopenharmony_ci if (IS_ERR(chan)) { 115862306a36Sopenharmony_ci err = PTR_ERR(chan); 115962306a36Sopenharmony_ci goto err_no_rxchan; 116062306a36Sopenharmony_ci } 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci pl022->dma_rx_channel = chan; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci chan = dma_request_chan(dev, "tx"); 116562306a36Sopenharmony_ci if (IS_ERR(chan)) { 116662306a36Sopenharmony_ci err = PTR_ERR(chan); 116762306a36Sopenharmony_ci goto err_no_txchan; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci pl022->dma_tx_channel = chan; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL); 117362306a36Sopenharmony_ci if (!pl022->dummypage) { 117462306a36Sopenharmony_ci err = -ENOMEM; 117562306a36Sopenharmony_ci goto err_no_dummypage; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci return 0; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cierr_no_dummypage: 118162306a36Sopenharmony_ci dma_release_channel(pl022->dma_tx_channel); 118262306a36Sopenharmony_ci pl022->dma_tx_channel = NULL; 118362306a36Sopenharmony_cierr_no_txchan: 118462306a36Sopenharmony_ci dma_release_channel(pl022->dma_rx_channel); 118562306a36Sopenharmony_ci pl022->dma_rx_channel = NULL; 118662306a36Sopenharmony_cierr_no_rxchan: 118762306a36Sopenharmony_ci return err; 118862306a36Sopenharmony_ci} 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_cistatic void terminate_dma(struct pl022 *pl022) 119162306a36Sopenharmony_ci{ 119262306a36Sopenharmony_ci struct dma_chan *rxchan = pl022->dma_rx_channel; 119362306a36Sopenharmony_ci struct dma_chan *txchan = pl022->dma_tx_channel; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci dmaengine_terminate_all(rxchan); 119662306a36Sopenharmony_ci dmaengine_terminate_all(txchan); 119762306a36Sopenharmony_ci unmap_free_dma_scatter(pl022); 119862306a36Sopenharmony_ci pl022->dma_running = false; 119962306a36Sopenharmony_ci} 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic void pl022_dma_remove(struct pl022 *pl022) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci if (pl022->dma_running) 120462306a36Sopenharmony_ci terminate_dma(pl022); 120562306a36Sopenharmony_ci if (pl022->dma_tx_channel) 120662306a36Sopenharmony_ci dma_release_channel(pl022->dma_tx_channel); 120762306a36Sopenharmony_ci if (pl022->dma_rx_channel) 120862306a36Sopenharmony_ci dma_release_channel(pl022->dma_rx_channel); 120962306a36Sopenharmony_ci kfree(pl022->dummypage); 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci#else 121362306a36Sopenharmony_cistatic inline int configure_dma(struct pl022 *pl022) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci return -ENODEV; 121662306a36Sopenharmony_ci} 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_cistatic inline int pl022_dma_autoprobe(struct pl022 *pl022) 121962306a36Sopenharmony_ci{ 122062306a36Sopenharmony_ci return 0; 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic inline int pl022_dma_probe(struct pl022 *pl022) 122462306a36Sopenharmony_ci{ 122562306a36Sopenharmony_ci return 0; 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_cistatic inline void pl022_dma_remove(struct pl022 *pl022) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci} 123162306a36Sopenharmony_ci#endif 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci/** 123462306a36Sopenharmony_ci * pl022_interrupt_handler - Interrupt handler for SSP controller 123562306a36Sopenharmony_ci * @irq: IRQ number 123662306a36Sopenharmony_ci * @dev_id: Local device data 123762306a36Sopenharmony_ci * 123862306a36Sopenharmony_ci * This function handles interrupts generated for an interrupt based transfer. 123962306a36Sopenharmony_ci * If a receive overrun (ROR) interrupt is there then we disable SSP, flag the 124062306a36Sopenharmony_ci * current message's state as STATE_ERROR and schedule the tasklet 124162306a36Sopenharmony_ci * pump_transfers which will do the postprocessing of the current message by 124262306a36Sopenharmony_ci * calling giveback(). Otherwise it reads data from RX FIFO till there is no 124362306a36Sopenharmony_ci * more data, and writes data in TX FIFO till it is not full. If we complete 124462306a36Sopenharmony_ci * the transfer we move to the next transfer and schedule the tasklet. 124562306a36Sopenharmony_ci */ 124662306a36Sopenharmony_cistatic irqreturn_t pl022_interrupt_handler(int irq, void *dev_id) 124762306a36Sopenharmony_ci{ 124862306a36Sopenharmony_ci struct pl022 *pl022 = dev_id; 124962306a36Sopenharmony_ci struct spi_message *msg = pl022->cur_msg; 125062306a36Sopenharmony_ci u16 irq_status = 0; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci if (unlikely(!msg)) { 125362306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 125462306a36Sopenharmony_ci "bad message state in interrupt handler"); 125562306a36Sopenharmony_ci /* Never fail */ 125662306a36Sopenharmony_ci return IRQ_HANDLED; 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* Read the Interrupt Status Register */ 126062306a36Sopenharmony_ci irq_status = readw(SSP_MIS(pl022->virtbase)); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci if (unlikely(!irq_status)) 126362306a36Sopenharmony_ci return IRQ_NONE; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci /* 126662306a36Sopenharmony_ci * This handles the FIFO interrupts, the timeout 126762306a36Sopenharmony_ci * interrupts are flatly ignored, they cannot be 126862306a36Sopenharmony_ci * trusted. 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_ci if (unlikely(irq_status & SSP_MIS_MASK_RORMIS)) { 127162306a36Sopenharmony_ci /* 127262306a36Sopenharmony_ci * Overrun interrupt - bail out since our Data has been 127362306a36Sopenharmony_ci * corrupted 127462306a36Sopenharmony_ci */ 127562306a36Sopenharmony_ci dev_err(&pl022->adev->dev, "FIFO overrun\n"); 127662306a36Sopenharmony_ci if (readw(SSP_SR(pl022->virtbase)) & SSP_SR_MASK_RFF) 127762306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 127862306a36Sopenharmony_ci "RXFIFO is full\n"); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* 128162306a36Sopenharmony_ci * Disable and clear interrupts, disable SSP, 128262306a36Sopenharmony_ci * mark message with bad status so it can be 128362306a36Sopenharmony_ci * retried. 128462306a36Sopenharmony_ci */ 128562306a36Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, 128662306a36Sopenharmony_ci SSP_IMSC(pl022->virtbase)); 128762306a36Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 128862306a36Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & 128962306a36Sopenharmony_ci (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); 129062306a36Sopenharmony_ci msg->state = STATE_ERROR; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* Schedule message queue handler */ 129362306a36Sopenharmony_ci tasklet_schedule(&pl022->pump_transfers); 129462306a36Sopenharmony_ci return IRQ_HANDLED; 129562306a36Sopenharmony_ci } 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci readwriter(pl022); 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci if (pl022->tx == pl022->tx_end) { 130062306a36Sopenharmony_ci /* Disable Transmit interrupt, enable receive interrupt */ 130162306a36Sopenharmony_ci writew((readw(SSP_IMSC(pl022->virtbase)) & 130262306a36Sopenharmony_ci ~SSP_IMSC_MASK_TXIM) | SSP_IMSC_MASK_RXIM, 130362306a36Sopenharmony_ci SSP_IMSC(pl022->virtbase)); 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci /* 130762306a36Sopenharmony_ci * Since all transactions must write as much as shall be read, 130862306a36Sopenharmony_ci * we can conclude the entire transaction once RX is complete. 130962306a36Sopenharmony_ci * At this point, all TX will always be finished. 131062306a36Sopenharmony_ci */ 131162306a36Sopenharmony_ci if (pl022->rx >= pl022->rx_end) { 131262306a36Sopenharmony_ci writew(DISABLE_ALL_INTERRUPTS, 131362306a36Sopenharmony_ci SSP_IMSC(pl022->virtbase)); 131462306a36Sopenharmony_ci writew(CLEAR_ALL_INTERRUPTS, SSP_ICR(pl022->virtbase)); 131562306a36Sopenharmony_ci if (unlikely(pl022->rx > pl022->rx_end)) { 131662306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, "read %u surplus " 131762306a36Sopenharmony_ci "bytes (did you request an odd " 131862306a36Sopenharmony_ci "number of bytes on a 16bit bus?)\n", 131962306a36Sopenharmony_ci (u32) (pl022->rx - pl022->rx_end)); 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci /* Update total bytes transferred */ 132262306a36Sopenharmony_ci msg->actual_length += pl022->cur_transfer->len; 132362306a36Sopenharmony_ci /* Move to next transfer */ 132462306a36Sopenharmony_ci msg->state = next_transfer(pl022); 132562306a36Sopenharmony_ci if (msg->state != STATE_DONE && pl022->cur_transfer->cs_change) 132662306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 132762306a36Sopenharmony_ci tasklet_schedule(&pl022->pump_transfers); 132862306a36Sopenharmony_ci return IRQ_HANDLED; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci return IRQ_HANDLED; 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci/* 133562306a36Sopenharmony_ci * This sets up the pointers to memory for the next message to 133662306a36Sopenharmony_ci * send out on the SPI bus. 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_cistatic int set_up_next_transfer(struct pl022 *pl022, 133962306a36Sopenharmony_ci struct spi_transfer *transfer) 134062306a36Sopenharmony_ci{ 134162306a36Sopenharmony_ci int residue; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci /* Sanity check the message for this bus width */ 134462306a36Sopenharmony_ci residue = pl022->cur_transfer->len % pl022->cur_chip->n_bytes; 134562306a36Sopenharmony_ci if (unlikely(residue != 0)) { 134662306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 134762306a36Sopenharmony_ci "message of %u bytes to transmit but the current " 134862306a36Sopenharmony_ci "chip bus has a data width of %u bytes!\n", 134962306a36Sopenharmony_ci pl022->cur_transfer->len, 135062306a36Sopenharmony_ci pl022->cur_chip->n_bytes); 135162306a36Sopenharmony_ci dev_err(&pl022->adev->dev, "skipping this message\n"); 135262306a36Sopenharmony_ci return -EIO; 135362306a36Sopenharmony_ci } 135462306a36Sopenharmony_ci pl022->tx = (void *)transfer->tx_buf; 135562306a36Sopenharmony_ci pl022->tx_end = pl022->tx + pl022->cur_transfer->len; 135662306a36Sopenharmony_ci pl022->rx = (void *)transfer->rx_buf; 135762306a36Sopenharmony_ci pl022->rx_end = pl022->rx + pl022->cur_transfer->len; 135862306a36Sopenharmony_ci pl022->write = 135962306a36Sopenharmony_ci pl022->tx ? pl022->cur_chip->write : WRITING_NULL; 136062306a36Sopenharmony_ci pl022->read = pl022->rx ? pl022->cur_chip->read : READING_NULL; 136162306a36Sopenharmony_ci return 0; 136262306a36Sopenharmony_ci} 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci/** 136562306a36Sopenharmony_ci * pump_transfers - Tasklet function which schedules next transfer 136662306a36Sopenharmony_ci * when running in interrupt or DMA transfer mode. 136762306a36Sopenharmony_ci * @data: SSP driver private data structure 136862306a36Sopenharmony_ci * 136962306a36Sopenharmony_ci */ 137062306a36Sopenharmony_cistatic void pump_transfers(unsigned long data) 137162306a36Sopenharmony_ci{ 137262306a36Sopenharmony_ci struct pl022 *pl022 = (struct pl022 *) data; 137362306a36Sopenharmony_ci struct spi_message *message = NULL; 137462306a36Sopenharmony_ci struct spi_transfer *transfer = NULL; 137562306a36Sopenharmony_ci struct spi_transfer *previous = NULL; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci /* Get current state information */ 137862306a36Sopenharmony_ci message = pl022->cur_msg; 137962306a36Sopenharmony_ci transfer = pl022->cur_transfer; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci /* Handle for abort */ 138262306a36Sopenharmony_ci if (message->state == STATE_ERROR) { 138362306a36Sopenharmony_ci message->status = -EIO; 138462306a36Sopenharmony_ci giveback(pl022); 138562306a36Sopenharmony_ci return; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci /* Handle end of message */ 138962306a36Sopenharmony_ci if (message->state == STATE_DONE) { 139062306a36Sopenharmony_ci message->status = 0; 139162306a36Sopenharmony_ci giveback(pl022); 139262306a36Sopenharmony_ci return; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci /* Delay if requested at end of transfer before CS change */ 139662306a36Sopenharmony_ci if (message->state == STATE_RUNNING) { 139762306a36Sopenharmony_ci previous = list_entry(transfer->transfer_list.prev, 139862306a36Sopenharmony_ci struct spi_transfer, 139962306a36Sopenharmony_ci transfer_list); 140062306a36Sopenharmony_ci /* 140162306a36Sopenharmony_ci * FIXME: This runs in interrupt context. 140262306a36Sopenharmony_ci * Is this really smart? 140362306a36Sopenharmony_ci */ 140462306a36Sopenharmony_ci spi_transfer_delay_exec(previous); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci /* Reselect chip select only if cs_change was requested */ 140762306a36Sopenharmony_ci if (previous->cs_change) 140862306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 140962306a36Sopenharmony_ci } else { 141062306a36Sopenharmony_ci /* STATE_START */ 141162306a36Sopenharmony_ci message->state = STATE_RUNNING; 141262306a36Sopenharmony_ci } 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (set_up_next_transfer(pl022, transfer)) { 141562306a36Sopenharmony_ci message->state = STATE_ERROR; 141662306a36Sopenharmony_ci message->status = -EIO; 141762306a36Sopenharmony_ci giveback(pl022); 141862306a36Sopenharmony_ci return; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci /* Flush the FIFOs and let's go! */ 142162306a36Sopenharmony_ci flush(pl022); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (pl022->cur_chip->enable_dma) { 142462306a36Sopenharmony_ci if (configure_dma(pl022)) { 142562306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, 142662306a36Sopenharmony_ci "configuration of DMA failed, fall back to interrupt mode\n"); 142762306a36Sopenharmony_ci goto err_config_dma; 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci return; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_cierr_config_dma: 143362306a36Sopenharmony_ci /* enable all interrupts except RX */ 143462306a36Sopenharmony_ci writew(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM, SSP_IMSC(pl022->virtbase)); 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_cistatic void do_interrupt_dma_transfer(struct pl022 *pl022) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci /* 144062306a36Sopenharmony_ci * Default is to enable all interrupts except RX - 144162306a36Sopenharmony_ci * this will be enabled once TX is complete 144262306a36Sopenharmony_ci */ 144362306a36Sopenharmony_ci u32 irqflags = (u32)(ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci /* Enable target chip, if not already active */ 144662306a36Sopenharmony_ci if (!pl022->next_msg_cs_active) 144762306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci if (set_up_next_transfer(pl022, pl022->cur_transfer)) { 145062306a36Sopenharmony_ci /* Error path */ 145162306a36Sopenharmony_ci pl022->cur_msg->state = STATE_ERROR; 145262306a36Sopenharmony_ci pl022->cur_msg->status = -EIO; 145362306a36Sopenharmony_ci giveback(pl022); 145462306a36Sopenharmony_ci return; 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci /* If we're using DMA, set up DMA here */ 145762306a36Sopenharmony_ci if (pl022->cur_chip->enable_dma) { 145862306a36Sopenharmony_ci /* Configure DMA transfer */ 145962306a36Sopenharmony_ci if (configure_dma(pl022)) { 146062306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, 146162306a36Sopenharmony_ci "configuration of DMA failed, fall back to interrupt mode\n"); 146262306a36Sopenharmony_ci goto err_config_dma; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci /* Disable interrupts in DMA mode, IRQ from DMA controller */ 146562306a36Sopenharmony_ci irqflags = DISABLE_ALL_INTERRUPTS; 146662306a36Sopenharmony_ci } 146762306a36Sopenharmony_cierr_config_dma: 146862306a36Sopenharmony_ci /* Enable SSP, turn on interrupts */ 146962306a36Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), 147062306a36Sopenharmony_ci SSP_CR1(pl022->virtbase)); 147162306a36Sopenharmony_ci writew(irqflags, SSP_IMSC(pl022->virtbase)); 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_cistatic void print_current_status(struct pl022 *pl022) 147562306a36Sopenharmony_ci{ 147662306a36Sopenharmony_ci u32 read_cr0; 147762306a36Sopenharmony_ci u16 read_cr1, read_dmacr, read_sr; 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci if (pl022->vendor->extended_cr) 148062306a36Sopenharmony_ci read_cr0 = readl(SSP_CR0(pl022->virtbase)); 148162306a36Sopenharmony_ci else 148262306a36Sopenharmony_ci read_cr0 = readw(SSP_CR0(pl022->virtbase)); 148362306a36Sopenharmony_ci read_cr1 = readw(SSP_CR1(pl022->virtbase)); 148462306a36Sopenharmony_ci read_dmacr = readw(SSP_DMACR(pl022->virtbase)); 148562306a36Sopenharmony_ci read_sr = readw(SSP_SR(pl022->virtbase)); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 CR0: %x\n", read_cr0); 148862306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 CR1: %x\n", read_cr1); 148962306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 DMACR: %x\n", read_dmacr); 149062306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, "spi-pl022 SR: %x\n", read_sr); 149162306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, 149262306a36Sopenharmony_ci "spi-pl022 exp_fifo_level/fifodepth: %u/%d\n", 149362306a36Sopenharmony_ci pl022->exp_fifo_level, 149462306a36Sopenharmony_ci pl022->vendor->fifodepth); 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci} 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cistatic void do_polling_transfer(struct pl022 *pl022) 149962306a36Sopenharmony_ci{ 150062306a36Sopenharmony_ci struct spi_message *message = NULL; 150162306a36Sopenharmony_ci struct spi_transfer *transfer = NULL; 150262306a36Sopenharmony_ci struct spi_transfer *previous = NULL; 150362306a36Sopenharmony_ci unsigned long time, timeout; 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci message = pl022->cur_msg; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci while (message->state != STATE_DONE) { 150862306a36Sopenharmony_ci /* Handle for abort */ 150962306a36Sopenharmony_ci if (message->state == STATE_ERROR) 151062306a36Sopenharmony_ci break; 151162306a36Sopenharmony_ci transfer = pl022->cur_transfer; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci /* Delay if requested at end of transfer */ 151462306a36Sopenharmony_ci if (message->state == STATE_RUNNING) { 151562306a36Sopenharmony_ci previous = 151662306a36Sopenharmony_ci list_entry(transfer->transfer_list.prev, 151762306a36Sopenharmony_ci struct spi_transfer, transfer_list); 151862306a36Sopenharmony_ci spi_transfer_delay_exec(previous); 151962306a36Sopenharmony_ci if (previous->cs_change) 152062306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 152162306a36Sopenharmony_ci } else { 152262306a36Sopenharmony_ci /* STATE_START */ 152362306a36Sopenharmony_ci message->state = STATE_RUNNING; 152462306a36Sopenharmony_ci if (!pl022->next_msg_cs_active) 152562306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_SELECT); 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci 152862306a36Sopenharmony_ci /* Configuration Changing Per Transfer */ 152962306a36Sopenharmony_ci if (set_up_next_transfer(pl022, transfer)) { 153062306a36Sopenharmony_ci /* Error path */ 153162306a36Sopenharmony_ci message->state = STATE_ERROR; 153262306a36Sopenharmony_ci break; 153362306a36Sopenharmony_ci } 153462306a36Sopenharmony_ci /* Flush FIFOs and enable SSP */ 153562306a36Sopenharmony_ci flush(pl022); 153662306a36Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) | SSP_CR1_MASK_SSE), 153762306a36Sopenharmony_ci SSP_CR1(pl022->virtbase)); 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "polling transfer ongoing ...\n"); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(SPI_POLLING_TIMEOUT); 154262306a36Sopenharmony_ci while (pl022->tx < pl022->tx_end || pl022->rx < pl022->rx_end) { 154362306a36Sopenharmony_ci time = jiffies; 154462306a36Sopenharmony_ci readwriter(pl022); 154562306a36Sopenharmony_ci if (time_after(time, timeout)) { 154662306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, 154762306a36Sopenharmony_ci "%s: timeout!\n", __func__); 154862306a36Sopenharmony_ci message->state = STATE_TIMEOUT; 154962306a36Sopenharmony_ci print_current_status(pl022); 155062306a36Sopenharmony_ci goto out; 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci cpu_relax(); 155362306a36Sopenharmony_ci } 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci /* Update total byte transferred */ 155662306a36Sopenharmony_ci message->actual_length += pl022->cur_transfer->len; 155762306a36Sopenharmony_ci /* Move to next transfer */ 155862306a36Sopenharmony_ci message->state = next_transfer(pl022); 155962306a36Sopenharmony_ci if (message->state != STATE_DONE 156062306a36Sopenharmony_ci && pl022->cur_transfer->cs_change) 156162306a36Sopenharmony_ci pl022_cs_control(pl022, SSP_CHIP_DESELECT); 156262306a36Sopenharmony_ci } 156362306a36Sopenharmony_ciout: 156462306a36Sopenharmony_ci /* Handle end of message */ 156562306a36Sopenharmony_ci if (message->state == STATE_DONE) 156662306a36Sopenharmony_ci message->status = 0; 156762306a36Sopenharmony_ci else if (message->state == STATE_TIMEOUT) 156862306a36Sopenharmony_ci message->status = -EAGAIN; 156962306a36Sopenharmony_ci else 157062306a36Sopenharmony_ci message->status = -EIO; 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci giveback(pl022); 157362306a36Sopenharmony_ci return; 157462306a36Sopenharmony_ci} 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_cistatic int pl022_transfer_one_message(struct spi_controller *host, 157762306a36Sopenharmony_ci struct spi_message *msg) 157862306a36Sopenharmony_ci{ 157962306a36Sopenharmony_ci struct pl022 *pl022 = spi_controller_get_devdata(host); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci /* Initial message state */ 158262306a36Sopenharmony_ci pl022->cur_msg = msg; 158362306a36Sopenharmony_ci msg->state = STATE_START; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci pl022->cur_transfer = list_entry(msg->transfers.next, 158662306a36Sopenharmony_ci struct spi_transfer, transfer_list); 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci /* Setup the SPI using the per chip configuration */ 158962306a36Sopenharmony_ci pl022->cur_chip = spi_get_ctldata(msg->spi); 159062306a36Sopenharmony_ci pl022->cur_cs = spi_get_chipselect(msg->spi, 0); 159162306a36Sopenharmony_ci /* This is always available but may be set to -ENOENT */ 159262306a36Sopenharmony_ci pl022->cur_gpiod = spi_get_csgpiod(msg->spi, 0); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci restore_state(pl022); 159562306a36Sopenharmony_ci flush(pl022); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci if (pl022->cur_chip->xfer_type == POLLING_TRANSFER) 159862306a36Sopenharmony_ci do_polling_transfer(pl022); 159962306a36Sopenharmony_ci else 160062306a36Sopenharmony_ci do_interrupt_dma_transfer(pl022); 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci return 0; 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cistatic int pl022_unprepare_transfer_hardware(struct spi_controller *host) 160662306a36Sopenharmony_ci{ 160762306a36Sopenharmony_ci struct pl022 *pl022 = spi_controller_get_devdata(host); 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_ci /* nothing more to do - disable spi/ssp and power off */ 161062306a36Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & 161162306a36Sopenharmony_ci (~SSP_CR1_MASK_SSE)), SSP_CR1(pl022->virtbase)); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci return 0; 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic int verify_controller_parameters(struct pl022 *pl022, 161762306a36Sopenharmony_ci struct pl022_config_chip const *chip_info) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci if ((chip_info->iface < SSP_INTERFACE_MOTOROLA_SPI) 162062306a36Sopenharmony_ci || (chip_info->iface > SSP_INTERFACE_UNIDIRECTIONAL)) { 162162306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 162262306a36Sopenharmony_ci "interface is configured incorrectly\n"); 162362306a36Sopenharmony_ci return -EINVAL; 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci if ((chip_info->iface == SSP_INTERFACE_UNIDIRECTIONAL) && 162662306a36Sopenharmony_ci (!pl022->vendor->unidir)) { 162762306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 162862306a36Sopenharmony_ci "unidirectional mode not supported in this " 162962306a36Sopenharmony_ci "hardware version\n"); 163062306a36Sopenharmony_ci return -EINVAL; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci if ((chip_info->hierarchy != SSP_MASTER) 163362306a36Sopenharmony_ci && (chip_info->hierarchy != SSP_SLAVE)) { 163462306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 163562306a36Sopenharmony_ci "hierarchy is configured incorrectly\n"); 163662306a36Sopenharmony_ci return -EINVAL; 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci if ((chip_info->com_mode != INTERRUPT_TRANSFER) 163962306a36Sopenharmony_ci && (chip_info->com_mode != DMA_TRANSFER) 164062306a36Sopenharmony_ci && (chip_info->com_mode != POLLING_TRANSFER)) { 164162306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 164262306a36Sopenharmony_ci "Communication mode is configured incorrectly\n"); 164362306a36Sopenharmony_ci return -EINVAL; 164462306a36Sopenharmony_ci } 164562306a36Sopenharmony_ci switch (chip_info->rx_lev_trig) { 164662306a36Sopenharmony_ci case SSP_RX_1_OR_MORE_ELEM: 164762306a36Sopenharmony_ci case SSP_RX_4_OR_MORE_ELEM: 164862306a36Sopenharmony_ci case SSP_RX_8_OR_MORE_ELEM: 164962306a36Sopenharmony_ci /* These are always OK, all variants can handle this */ 165062306a36Sopenharmony_ci break; 165162306a36Sopenharmony_ci case SSP_RX_16_OR_MORE_ELEM: 165262306a36Sopenharmony_ci if (pl022->vendor->fifodepth < 16) { 165362306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 165462306a36Sopenharmony_ci "RX FIFO Trigger Level is configured incorrectly\n"); 165562306a36Sopenharmony_ci return -EINVAL; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci break; 165862306a36Sopenharmony_ci case SSP_RX_32_OR_MORE_ELEM: 165962306a36Sopenharmony_ci if (pl022->vendor->fifodepth < 32) { 166062306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 166162306a36Sopenharmony_ci "RX FIFO Trigger Level is configured incorrectly\n"); 166262306a36Sopenharmony_ci return -EINVAL; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci break; 166562306a36Sopenharmony_ci default: 166662306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 166762306a36Sopenharmony_ci "RX FIFO Trigger Level is configured incorrectly\n"); 166862306a36Sopenharmony_ci return -EINVAL; 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci switch (chip_info->tx_lev_trig) { 167162306a36Sopenharmony_ci case SSP_TX_1_OR_MORE_EMPTY_LOC: 167262306a36Sopenharmony_ci case SSP_TX_4_OR_MORE_EMPTY_LOC: 167362306a36Sopenharmony_ci case SSP_TX_8_OR_MORE_EMPTY_LOC: 167462306a36Sopenharmony_ci /* These are always OK, all variants can handle this */ 167562306a36Sopenharmony_ci break; 167662306a36Sopenharmony_ci case SSP_TX_16_OR_MORE_EMPTY_LOC: 167762306a36Sopenharmony_ci if (pl022->vendor->fifodepth < 16) { 167862306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 167962306a36Sopenharmony_ci "TX FIFO Trigger Level is configured incorrectly\n"); 168062306a36Sopenharmony_ci return -EINVAL; 168162306a36Sopenharmony_ci } 168262306a36Sopenharmony_ci break; 168362306a36Sopenharmony_ci case SSP_TX_32_OR_MORE_EMPTY_LOC: 168462306a36Sopenharmony_ci if (pl022->vendor->fifodepth < 32) { 168562306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 168662306a36Sopenharmony_ci "TX FIFO Trigger Level is configured incorrectly\n"); 168762306a36Sopenharmony_ci return -EINVAL; 168862306a36Sopenharmony_ci } 168962306a36Sopenharmony_ci break; 169062306a36Sopenharmony_ci default: 169162306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 169262306a36Sopenharmony_ci "TX FIFO Trigger Level is configured incorrectly\n"); 169362306a36Sopenharmony_ci return -EINVAL; 169462306a36Sopenharmony_ci } 169562306a36Sopenharmony_ci if (chip_info->iface == SSP_INTERFACE_NATIONAL_MICROWIRE) { 169662306a36Sopenharmony_ci if ((chip_info->ctrl_len < SSP_BITS_4) 169762306a36Sopenharmony_ci || (chip_info->ctrl_len > SSP_BITS_32)) { 169862306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 169962306a36Sopenharmony_ci "CTRL LEN is configured incorrectly\n"); 170062306a36Sopenharmony_ci return -EINVAL; 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci if ((chip_info->wait_state != SSP_MWIRE_WAIT_ZERO) 170362306a36Sopenharmony_ci && (chip_info->wait_state != SSP_MWIRE_WAIT_ONE)) { 170462306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 170562306a36Sopenharmony_ci "Wait State is configured incorrectly\n"); 170662306a36Sopenharmony_ci return -EINVAL; 170762306a36Sopenharmony_ci } 170862306a36Sopenharmony_ci /* Half duplex is only available in the ST Micro version */ 170962306a36Sopenharmony_ci if (pl022->vendor->extended_cr) { 171062306a36Sopenharmony_ci if ((chip_info->duplex != 171162306a36Sopenharmony_ci SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) 171262306a36Sopenharmony_ci && (chip_info->duplex != 171362306a36Sopenharmony_ci SSP_MICROWIRE_CHANNEL_HALF_DUPLEX)) { 171462306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 171562306a36Sopenharmony_ci "Microwire duplex mode is configured incorrectly\n"); 171662306a36Sopenharmony_ci return -EINVAL; 171762306a36Sopenharmony_ci } 171862306a36Sopenharmony_ci } else { 171962306a36Sopenharmony_ci if (chip_info->duplex != SSP_MICROWIRE_CHANNEL_FULL_DUPLEX) { 172062306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 172162306a36Sopenharmony_ci "Microwire half duplex mode requested," 172262306a36Sopenharmony_ci " but this is only available in the" 172362306a36Sopenharmony_ci " ST version of PL022\n"); 172462306a36Sopenharmony_ci return -EINVAL; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci return 0; 172962306a36Sopenharmony_ci} 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_cistatic inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr) 173262306a36Sopenharmony_ci{ 173362306a36Sopenharmony_ci return rate / (cpsdvsr * (1 + scr)); 173462306a36Sopenharmony_ci} 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_cistatic int calculate_effective_freq(struct pl022 *pl022, int freq, struct 173762306a36Sopenharmony_ci ssp_clock_params * clk_freq) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci /* Lets calculate the frequency parameters */ 174062306a36Sopenharmony_ci u16 cpsdvsr = CPSDVR_MIN, scr = SCR_MIN; 174162306a36Sopenharmony_ci u32 rate, max_tclk, min_tclk, best_freq = 0, best_cpsdvsr = 0, 174262306a36Sopenharmony_ci best_scr = 0, tmp, found = 0; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci rate = clk_get_rate(pl022->clk); 174562306a36Sopenharmony_ci /* cpsdvscr = 2 & scr 0 */ 174662306a36Sopenharmony_ci max_tclk = spi_rate(rate, CPSDVR_MIN, SCR_MIN); 174762306a36Sopenharmony_ci /* cpsdvsr = 254 & scr = 255 */ 174862306a36Sopenharmony_ci min_tclk = spi_rate(rate, CPSDVR_MAX, SCR_MAX); 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (freq > max_tclk) 175162306a36Sopenharmony_ci dev_warn(&pl022->adev->dev, 175262306a36Sopenharmony_ci "Max speed that can be programmed is %d Hz, you requested %d\n", 175362306a36Sopenharmony_ci max_tclk, freq); 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci if (freq < min_tclk) { 175662306a36Sopenharmony_ci dev_err(&pl022->adev->dev, 175762306a36Sopenharmony_ci "Requested frequency: %d Hz is less than minimum possible %d Hz\n", 175862306a36Sopenharmony_ci freq, min_tclk); 175962306a36Sopenharmony_ci return -EINVAL; 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci /* 176362306a36Sopenharmony_ci * best_freq will give closest possible available rate (<= requested 176462306a36Sopenharmony_ci * freq) for all values of scr & cpsdvsr. 176562306a36Sopenharmony_ci */ 176662306a36Sopenharmony_ci while ((cpsdvsr <= CPSDVR_MAX) && !found) { 176762306a36Sopenharmony_ci while (scr <= SCR_MAX) { 176862306a36Sopenharmony_ci tmp = spi_rate(rate, cpsdvsr, scr); 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (tmp > freq) { 177162306a36Sopenharmony_ci /* we need lower freq */ 177262306a36Sopenharmony_ci scr++; 177362306a36Sopenharmony_ci continue; 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci /* 177762306a36Sopenharmony_ci * If found exact value, mark found and break. 177862306a36Sopenharmony_ci * If found more closer value, update and break. 177962306a36Sopenharmony_ci */ 178062306a36Sopenharmony_ci if (tmp > best_freq) { 178162306a36Sopenharmony_ci best_freq = tmp; 178262306a36Sopenharmony_ci best_cpsdvsr = cpsdvsr; 178362306a36Sopenharmony_ci best_scr = scr; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci if (tmp == freq) 178662306a36Sopenharmony_ci found = 1; 178762306a36Sopenharmony_ci } 178862306a36Sopenharmony_ci /* 178962306a36Sopenharmony_ci * increased scr will give lower rates, which are not 179062306a36Sopenharmony_ci * required 179162306a36Sopenharmony_ci */ 179262306a36Sopenharmony_ci break; 179362306a36Sopenharmony_ci } 179462306a36Sopenharmony_ci cpsdvsr += 2; 179562306a36Sopenharmony_ci scr = SCR_MIN; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci WARN(!best_freq, "pl022: Matching cpsdvsr and scr not found for %d Hz rate \n", 179962306a36Sopenharmony_ci freq); 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci clk_freq->cpsdvsr = (u8) (best_cpsdvsr & 0xFF); 180262306a36Sopenharmony_ci clk_freq->scr = (u8) (best_scr & 0xFF); 180362306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, 180462306a36Sopenharmony_ci "SSP Target Frequency is: %u, Effective Frequency is %u\n", 180562306a36Sopenharmony_ci freq, best_freq); 180662306a36Sopenharmony_ci dev_dbg(&pl022->adev->dev, "SSP cpsdvsr = %d, scr = %d\n", 180762306a36Sopenharmony_ci clk_freq->cpsdvsr, clk_freq->scr); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci return 0; 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci/* 181362306a36Sopenharmony_ci * A piece of default chip info unless the platform 181462306a36Sopenharmony_ci * supplies it. 181562306a36Sopenharmony_ci */ 181662306a36Sopenharmony_cistatic const struct pl022_config_chip pl022_default_chip_info = { 181762306a36Sopenharmony_ci .com_mode = INTERRUPT_TRANSFER, 181862306a36Sopenharmony_ci .iface = SSP_INTERFACE_MOTOROLA_SPI, 181962306a36Sopenharmony_ci .hierarchy = SSP_MASTER, 182062306a36Sopenharmony_ci .slave_tx_disable = DO_NOT_DRIVE_TX, 182162306a36Sopenharmony_ci .rx_lev_trig = SSP_RX_1_OR_MORE_ELEM, 182262306a36Sopenharmony_ci .tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC, 182362306a36Sopenharmony_ci .ctrl_len = SSP_BITS_8, 182462306a36Sopenharmony_ci .wait_state = SSP_MWIRE_WAIT_ZERO, 182562306a36Sopenharmony_ci .duplex = SSP_MICROWIRE_CHANNEL_FULL_DUPLEX, 182662306a36Sopenharmony_ci}; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci/** 182962306a36Sopenharmony_ci * pl022_setup - setup function registered to SPI host framework 183062306a36Sopenharmony_ci * @spi: spi device which is requesting setup 183162306a36Sopenharmony_ci * 183262306a36Sopenharmony_ci * This function is registered to the SPI framework for this SPI host 183362306a36Sopenharmony_ci * controller. If it is the first time when setup is called by this device, 183462306a36Sopenharmony_ci * this function will initialize the runtime state for this chip and save 183562306a36Sopenharmony_ci * the same in the device structure. Else it will update the runtime info 183662306a36Sopenharmony_ci * with the updated chip info. Nothing is really being written to the 183762306a36Sopenharmony_ci * controller hardware here, that is not done until the actual transfer 183862306a36Sopenharmony_ci * commence. 183962306a36Sopenharmony_ci */ 184062306a36Sopenharmony_cistatic int pl022_setup(struct spi_device *spi) 184162306a36Sopenharmony_ci{ 184262306a36Sopenharmony_ci struct pl022_config_chip const *chip_info; 184362306a36Sopenharmony_ci struct pl022_config_chip chip_info_dt; 184462306a36Sopenharmony_ci struct chip_data *chip; 184562306a36Sopenharmony_ci struct ssp_clock_params clk_freq = { .cpsdvsr = 0, .scr = 0}; 184662306a36Sopenharmony_ci int status = 0; 184762306a36Sopenharmony_ci struct pl022 *pl022 = spi_controller_get_devdata(spi->controller); 184862306a36Sopenharmony_ci unsigned int bits = spi->bits_per_word; 184962306a36Sopenharmony_ci u32 tmp; 185062306a36Sopenharmony_ci struct device_node *np = spi->dev.of_node; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci if (!spi->max_speed_hz) 185362306a36Sopenharmony_ci return -EINVAL; 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci /* Get controller_state if one is supplied */ 185662306a36Sopenharmony_ci chip = spi_get_ctldata(spi); 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_ci if (chip == NULL) { 185962306a36Sopenharmony_ci chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL); 186062306a36Sopenharmony_ci if (!chip) 186162306a36Sopenharmony_ci return -ENOMEM; 186262306a36Sopenharmony_ci dev_dbg(&spi->dev, 186362306a36Sopenharmony_ci "allocated memory for controller's runtime state\n"); 186462306a36Sopenharmony_ci } 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci /* Get controller data if one is supplied */ 186762306a36Sopenharmony_ci chip_info = spi->controller_data; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci if (chip_info == NULL) { 187062306a36Sopenharmony_ci if (np) { 187162306a36Sopenharmony_ci chip_info_dt = pl022_default_chip_info; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci chip_info_dt.hierarchy = SSP_MASTER; 187462306a36Sopenharmony_ci of_property_read_u32(np, "pl022,interface", 187562306a36Sopenharmony_ci &chip_info_dt.iface); 187662306a36Sopenharmony_ci of_property_read_u32(np, "pl022,com-mode", 187762306a36Sopenharmony_ci &chip_info_dt.com_mode); 187862306a36Sopenharmony_ci of_property_read_u32(np, "pl022,rx-level-trig", 187962306a36Sopenharmony_ci &chip_info_dt.rx_lev_trig); 188062306a36Sopenharmony_ci of_property_read_u32(np, "pl022,tx-level-trig", 188162306a36Sopenharmony_ci &chip_info_dt.tx_lev_trig); 188262306a36Sopenharmony_ci of_property_read_u32(np, "pl022,ctrl-len", 188362306a36Sopenharmony_ci &chip_info_dt.ctrl_len); 188462306a36Sopenharmony_ci of_property_read_u32(np, "pl022,wait-state", 188562306a36Sopenharmony_ci &chip_info_dt.wait_state); 188662306a36Sopenharmony_ci of_property_read_u32(np, "pl022,duplex", 188762306a36Sopenharmony_ci &chip_info_dt.duplex); 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci chip_info = &chip_info_dt; 189062306a36Sopenharmony_ci } else { 189162306a36Sopenharmony_ci chip_info = &pl022_default_chip_info; 189262306a36Sopenharmony_ci /* spi_board_info.controller_data not is supplied */ 189362306a36Sopenharmony_ci dev_dbg(&spi->dev, 189462306a36Sopenharmony_ci "using default controller_data settings\n"); 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci } else 189762306a36Sopenharmony_ci dev_dbg(&spi->dev, 189862306a36Sopenharmony_ci "using user supplied controller_data settings\n"); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci /* 190162306a36Sopenharmony_ci * We can override with custom divisors, else we use the board 190262306a36Sopenharmony_ci * frequency setting 190362306a36Sopenharmony_ci */ 190462306a36Sopenharmony_ci if ((0 == chip_info->clk_freq.cpsdvsr) 190562306a36Sopenharmony_ci && (0 == chip_info->clk_freq.scr)) { 190662306a36Sopenharmony_ci status = calculate_effective_freq(pl022, 190762306a36Sopenharmony_ci spi->max_speed_hz, 190862306a36Sopenharmony_ci &clk_freq); 190962306a36Sopenharmony_ci if (status < 0) 191062306a36Sopenharmony_ci goto err_config_params; 191162306a36Sopenharmony_ci } else { 191262306a36Sopenharmony_ci memcpy(&clk_freq, &chip_info->clk_freq, sizeof(clk_freq)); 191362306a36Sopenharmony_ci if ((clk_freq.cpsdvsr % 2) != 0) 191462306a36Sopenharmony_ci clk_freq.cpsdvsr = 191562306a36Sopenharmony_ci clk_freq.cpsdvsr - 1; 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci if ((clk_freq.cpsdvsr < CPSDVR_MIN) 191862306a36Sopenharmony_ci || (clk_freq.cpsdvsr > CPSDVR_MAX)) { 191962306a36Sopenharmony_ci status = -EINVAL; 192062306a36Sopenharmony_ci dev_err(&spi->dev, 192162306a36Sopenharmony_ci "cpsdvsr is configured incorrectly\n"); 192262306a36Sopenharmony_ci goto err_config_params; 192362306a36Sopenharmony_ci } 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci status = verify_controller_parameters(pl022, chip_info); 192662306a36Sopenharmony_ci if (status) { 192762306a36Sopenharmony_ci dev_err(&spi->dev, "controller data is incorrect"); 192862306a36Sopenharmony_ci goto err_config_params; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci pl022->rx_lev_trig = chip_info->rx_lev_trig; 193262306a36Sopenharmony_ci pl022->tx_lev_trig = chip_info->tx_lev_trig; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci /* Now set controller state based on controller data */ 193562306a36Sopenharmony_ci chip->xfer_type = chip_info->com_mode; 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci /* Check bits per word with vendor specific range */ 193862306a36Sopenharmony_ci if ((bits <= 3) || (bits > pl022->vendor->max_bpw)) { 193962306a36Sopenharmony_ci status = -ENOTSUPP; 194062306a36Sopenharmony_ci dev_err(&spi->dev, "illegal data size for this controller!\n"); 194162306a36Sopenharmony_ci dev_err(&spi->dev, "This controller can only handle 4 <= n <= %d bit words\n", 194262306a36Sopenharmony_ci pl022->vendor->max_bpw); 194362306a36Sopenharmony_ci goto err_config_params; 194462306a36Sopenharmony_ci } else if (bits <= 8) { 194562306a36Sopenharmony_ci dev_dbg(&spi->dev, "4 <= n <=8 bits per word\n"); 194662306a36Sopenharmony_ci chip->n_bytes = 1; 194762306a36Sopenharmony_ci chip->read = READING_U8; 194862306a36Sopenharmony_ci chip->write = WRITING_U8; 194962306a36Sopenharmony_ci } else if (bits <= 16) { 195062306a36Sopenharmony_ci dev_dbg(&spi->dev, "9 <= n <= 16 bits per word\n"); 195162306a36Sopenharmony_ci chip->n_bytes = 2; 195262306a36Sopenharmony_ci chip->read = READING_U16; 195362306a36Sopenharmony_ci chip->write = WRITING_U16; 195462306a36Sopenharmony_ci } else { 195562306a36Sopenharmony_ci dev_dbg(&spi->dev, "17 <= n <= 32 bits per word\n"); 195662306a36Sopenharmony_ci chip->n_bytes = 4; 195762306a36Sopenharmony_ci chip->read = READING_U32; 195862306a36Sopenharmony_ci chip->write = WRITING_U32; 195962306a36Sopenharmony_ci } 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci /* Now Initialize all register settings required for this chip */ 196262306a36Sopenharmony_ci chip->cr0 = 0; 196362306a36Sopenharmony_ci chip->cr1 = 0; 196462306a36Sopenharmony_ci chip->dmacr = 0; 196562306a36Sopenharmony_ci chip->cpsr = 0; 196662306a36Sopenharmony_ci if ((chip_info->com_mode == DMA_TRANSFER) 196762306a36Sopenharmony_ci && ((pl022->host_info)->enable_dma)) { 196862306a36Sopenharmony_ci chip->enable_dma = true; 196962306a36Sopenharmony_ci dev_dbg(&spi->dev, "DMA mode set in controller state\n"); 197062306a36Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, 197162306a36Sopenharmony_ci SSP_DMACR_MASK_RXDMAE, 0); 197262306a36Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_ENABLED, 197362306a36Sopenharmony_ci SSP_DMACR_MASK_TXDMAE, 1); 197462306a36Sopenharmony_ci } else { 197562306a36Sopenharmony_ci chip->enable_dma = false; 197662306a36Sopenharmony_ci dev_dbg(&spi->dev, "DMA mode NOT set in controller state\n"); 197762306a36Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED, 197862306a36Sopenharmony_ci SSP_DMACR_MASK_RXDMAE, 0); 197962306a36Sopenharmony_ci SSP_WRITE_BITS(chip->dmacr, SSP_DMA_DISABLED, 198062306a36Sopenharmony_ci SSP_DMACR_MASK_TXDMAE, 1); 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci chip->cpsr = clk_freq.cpsdvsr; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci /* Special setup for the ST micro extended control registers */ 198662306a36Sopenharmony_ci if (pl022->vendor->extended_cr) { 198762306a36Sopenharmony_ci u32 etx; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci if (pl022->vendor->pl023) { 199062306a36Sopenharmony_ci /* These bits are only in the PL023 */ 199162306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->clkdelay, 199262306a36Sopenharmony_ci SSP_CR1_MASK_FBCLKDEL_ST, 13); 199362306a36Sopenharmony_ci } else { 199462306a36Sopenharmony_ci /* These bits are in the PL022 but not PL023 */ 199562306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->duplex, 199662306a36Sopenharmony_ci SSP_CR0_MASK_HALFDUP_ST, 5); 199762306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->ctrl_len, 199862306a36Sopenharmony_ci SSP_CR0_MASK_CSS_ST, 16); 199962306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->iface, 200062306a36Sopenharmony_ci SSP_CR0_MASK_FRF_ST, 21); 200162306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->wait_state, 200262306a36Sopenharmony_ci SSP_CR1_MASK_MWAIT_ST, 6); 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, bits - 1, 200562306a36Sopenharmony_ci SSP_CR0_MASK_DSS_ST, 0); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (spi->mode & SPI_LSB_FIRST) { 200862306a36Sopenharmony_ci tmp = SSP_RX_LSB; 200962306a36Sopenharmony_ci etx = SSP_TX_LSB; 201062306a36Sopenharmony_ci } else { 201162306a36Sopenharmony_ci tmp = SSP_RX_MSB; 201262306a36Sopenharmony_ci etx = SSP_TX_MSB; 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_RENDN_ST, 4); 201562306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, etx, SSP_CR1_MASK_TENDN_ST, 5); 201662306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->rx_lev_trig, 201762306a36Sopenharmony_ci SSP_CR1_MASK_RXIFLSEL_ST, 7); 201862306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->tx_lev_trig, 201962306a36Sopenharmony_ci SSP_CR1_MASK_TXIFLSEL_ST, 10); 202062306a36Sopenharmony_ci } else { 202162306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, bits - 1, 202262306a36Sopenharmony_ci SSP_CR0_MASK_DSS, 0); 202362306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, chip_info->iface, 202462306a36Sopenharmony_ci SSP_CR0_MASK_FRF, 4); 202562306a36Sopenharmony_ci } 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci /* Stuff that is common for all versions */ 202862306a36Sopenharmony_ci if (spi->mode & SPI_CPOL) 202962306a36Sopenharmony_ci tmp = SSP_CLK_POL_IDLE_HIGH; 203062306a36Sopenharmony_ci else 203162306a36Sopenharmony_ci tmp = SSP_CLK_POL_IDLE_LOW; 203262306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPO, 6); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci if (spi->mode & SPI_CPHA) 203562306a36Sopenharmony_ci tmp = SSP_CLK_SECOND_EDGE; 203662306a36Sopenharmony_ci else 203762306a36Sopenharmony_ci tmp = SSP_CLK_FIRST_EDGE; 203862306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, tmp, SSP_CR0_MASK_SPH, 7); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr0, clk_freq.scr, SSP_CR0_MASK_SCR, 8); 204162306a36Sopenharmony_ci /* Loopback is available on all versions except PL023 */ 204262306a36Sopenharmony_ci if (pl022->vendor->loopback) { 204362306a36Sopenharmony_ci if (spi->mode & SPI_LOOP) 204462306a36Sopenharmony_ci tmp = LOOPBACK_ENABLED; 204562306a36Sopenharmony_ci else 204662306a36Sopenharmony_ci tmp = LOOPBACK_DISABLED; 204762306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, tmp, SSP_CR1_MASK_LBM, 0); 204862306a36Sopenharmony_ci } 204962306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, SSP_DISABLED, SSP_CR1_MASK_SSE, 1); 205062306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->hierarchy, SSP_CR1_MASK_MS, 2); 205162306a36Sopenharmony_ci SSP_WRITE_BITS(chip->cr1, chip_info->slave_tx_disable, SSP_CR1_MASK_SOD, 205262306a36Sopenharmony_ci 3); 205362306a36Sopenharmony_ci 205462306a36Sopenharmony_ci /* Save controller_state */ 205562306a36Sopenharmony_ci spi_set_ctldata(spi, chip); 205662306a36Sopenharmony_ci return status; 205762306a36Sopenharmony_ci err_config_params: 205862306a36Sopenharmony_ci spi_set_ctldata(spi, NULL); 205962306a36Sopenharmony_ci kfree(chip); 206062306a36Sopenharmony_ci return status; 206162306a36Sopenharmony_ci} 206262306a36Sopenharmony_ci 206362306a36Sopenharmony_ci/** 206462306a36Sopenharmony_ci * pl022_cleanup - cleanup function registered to SPI host framework 206562306a36Sopenharmony_ci * @spi: spi device which is requesting cleanup 206662306a36Sopenharmony_ci * 206762306a36Sopenharmony_ci * This function is registered to the SPI framework for this SPI host 206862306a36Sopenharmony_ci * controller. It will free the runtime state of chip. 206962306a36Sopenharmony_ci */ 207062306a36Sopenharmony_cistatic void pl022_cleanup(struct spi_device *spi) 207162306a36Sopenharmony_ci{ 207262306a36Sopenharmony_ci struct chip_data *chip = spi_get_ctldata(spi); 207362306a36Sopenharmony_ci 207462306a36Sopenharmony_ci spi_set_ctldata(spi, NULL); 207562306a36Sopenharmony_ci kfree(chip); 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic struct pl022_ssp_controller * 207962306a36Sopenharmony_cipl022_platform_data_dt_get(struct device *dev) 208062306a36Sopenharmony_ci{ 208162306a36Sopenharmony_ci struct device_node *np = dev->of_node; 208262306a36Sopenharmony_ci struct pl022_ssp_controller *pd; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci if (!np) { 208562306a36Sopenharmony_ci dev_err(dev, "no dt node defined\n"); 208662306a36Sopenharmony_ci return NULL; 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci pd = devm_kzalloc(dev, sizeof(struct pl022_ssp_controller), GFP_KERNEL); 209062306a36Sopenharmony_ci if (!pd) 209162306a36Sopenharmony_ci return NULL; 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci pd->bus_id = -1; 209462306a36Sopenharmony_ci of_property_read_u32(np, "pl022,autosuspend-delay", 209562306a36Sopenharmony_ci &pd->autosuspend_delay); 209662306a36Sopenharmony_ci pd->rt = of_property_read_bool(np, "pl022,rt"); 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci return pd; 209962306a36Sopenharmony_ci} 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_cistatic int pl022_probe(struct amba_device *adev, const struct amba_id *id) 210262306a36Sopenharmony_ci{ 210362306a36Sopenharmony_ci struct device *dev = &adev->dev; 210462306a36Sopenharmony_ci struct pl022_ssp_controller *platform_info = 210562306a36Sopenharmony_ci dev_get_platdata(&adev->dev); 210662306a36Sopenharmony_ci struct spi_controller *host; 210762306a36Sopenharmony_ci struct pl022 *pl022 = NULL; /*Data for this driver */ 210862306a36Sopenharmony_ci int status = 0; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci dev_info(&adev->dev, 211162306a36Sopenharmony_ci "ARM PL022 driver, device ID: 0x%08x\n", adev->periphid); 211262306a36Sopenharmony_ci if (!platform_info && IS_ENABLED(CONFIG_OF)) 211362306a36Sopenharmony_ci platform_info = pl022_platform_data_dt_get(dev); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci if (!platform_info) { 211662306a36Sopenharmony_ci dev_err(dev, "probe: no platform data defined\n"); 211762306a36Sopenharmony_ci return -ENODEV; 211862306a36Sopenharmony_ci } 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci /* Allocate host with space for data */ 212162306a36Sopenharmony_ci host = spi_alloc_host(dev, sizeof(struct pl022)); 212262306a36Sopenharmony_ci if (host == NULL) { 212362306a36Sopenharmony_ci dev_err(&adev->dev, "probe - cannot alloc SPI host\n"); 212462306a36Sopenharmony_ci return -ENOMEM; 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci pl022 = spi_controller_get_devdata(host); 212862306a36Sopenharmony_ci pl022->host = host; 212962306a36Sopenharmony_ci pl022->host_info = platform_info; 213062306a36Sopenharmony_ci pl022->adev = adev; 213162306a36Sopenharmony_ci pl022->vendor = id->data; 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_ci /* 213462306a36Sopenharmony_ci * Bus Number Which has been Assigned to this SSP controller 213562306a36Sopenharmony_ci * on this board 213662306a36Sopenharmony_ci */ 213762306a36Sopenharmony_ci host->bus_num = platform_info->bus_id; 213862306a36Sopenharmony_ci host->cleanup = pl022_cleanup; 213962306a36Sopenharmony_ci host->setup = pl022_setup; 214062306a36Sopenharmony_ci host->auto_runtime_pm = true; 214162306a36Sopenharmony_ci host->transfer_one_message = pl022_transfer_one_message; 214262306a36Sopenharmony_ci host->unprepare_transfer_hardware = pl022_unprepare_transfer_hardware; 214362306a36Sopenharmony_ci host->rt = platform_info->rt; 214462306a36Sopenharmony_ci host->dev.of_node = dev->of_node; 214562306a36Sopenharmony_ci host->use_gpio_descriptors = true; 214662306a36Sopenharmony_ci 214762306a36Sopenharmony_ci /* 214862306a36Sopenharmony_ci * Supports mode 0-3, loopback, and active low CS. Transfers are 214962306a36Sopenharmony_ci * always MS bit first on the original pl022. 215062306a36Sopenharmony_ci */ 215162306a36Sopenharmony_ci host->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP; 215262306a36Sopenharmony_ci if (pl022->vendor->extended_cr) 215362306a36Sopenharmony_ci host->mode_bits |= SPI_LSB_FIRST; 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci dev_dbg(&adev->dev, "BUSNO: %d\n", host->bus_num); 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci status = amba_request_regions(adev, NULL); 215862306a36Sopenharmony_ci if (status) 215962306a36Sopenharmony_ci goto err_no_ioregion; 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci pl022->phybase = adev->res.start; 216262306a36Sopenharmony_ci pl022->virtbase = devm_ioremap(dev, adev->res.start, 216362306a36Sopenharmony_ci resource_size(&adev->res)); 216462306a36Sopenharmony_ci if (pl022->virtbase == NULL) { 216562306a36Sopenharmony_ci status = -ENOMEM; 216662306a36Sopenharmony_ci goto err_no_ioremap; 216762306a36Sopenharmony_ci } 216862306a36Sopenharmony_ci dev_info(&adev->dev, "mapped registers from %pa to %p\n", 216962306a36Sopenharmony_ci &adev->res.start, pl022->virtbase); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci pl022->clk = devm_clk_get(&adev->dev, NULL); 217262306a36Sopenharmony_ci if (IS_ERR(pl022->clk)) { 217362306a36Sopenharmony_ci status = PTR_ERR(pl022->clk); 217462306a36Sopenharmony_ci dev_err(&adev->dev, "could not retrieve SSP/SPI bus clock\n"); 217562306a36Sopenharmony_ci goto err_no_clk; 217662306a36Sopenharmony_ci } 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci status = clk_prepare_enable(pl022->clk); 217962306a36Sopenharmony_ci if (status) { 218062306a36Sopenharmony_ci dev_err(&adev->dev, "could not enable SSP/SPI bus clock\n"); 218162306a36Sopenharmony_ci goto err_no_clk_en; 218262306a36Sopenharmony_ci } 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci /* Initialize transfer pump */ 218562306a36Sopenharmony_ci tasklet_init(&pl022->pump_transfers, pump_transfers, 218662306a36Sopenharmony_ci (unsigned long)pl022); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci /* Disable SSP */ 218962306a36Sopenharmony_ci writew((readw(SSP_CR1(pl022->virtbase)) & (~SSP_CR1_MASK_SSE)), 219062306a36Sopenharmony_ci SSP_CR1(pl022->virtbase)); 219162306a36Sopenharmony_ci load_ssp_default_config(pl022); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci status = devm_request_irq(dev, adev->irq[0], pl022_interrupt_handler, 219462306a36Sopenharmony_ci 0, "pl022", pl022); 219562306a36Sopenharmony_ci if (status < 0) { 219662306a36Sopenharmony_ci dev_err(&adev->dev, "probe - cannot get IRQ (%d)\n", status); 219762306a36Sopenharmony_ci goto err_no_irq; 219862306a36Sopenharmony_ci } 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci /* Get DMA channels, try autoconfiguration first */ 220162306a36Sopenharmony_ci status = pl022_dma_autoprobe(pl022); 220262306a36Sopenharmony_ci if (status == -EPROBE_DEFER) { 220362306a36Sopenharmony_ci dev_dbg(dev, "deferring probe to get DMA channel\n"); 220462306a36Sopenharmony_ci goto err_no_irq; 220562306a36Sopenharmony_ci } 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_ci /* If that failed, use channels from platform_info */ 220862306a36Sopenharmony_ci if (status == 0) 220962306a36Sopenharmony_ci platform_info->enable_dma = 1; 221062306a36Sopenharmony_ci else if (platform_info->enable_dma) { 221162306a36Sopenharmony_ci status = pl022_dma_probe(pl022); 221262306a36Sopenharmony_ci if (status != 0) 221362306a36Sopenharmony_ci platform_info->enable_dma = 0; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci /* Register with the SPI framework */ 221762306a36Sopenharmony_ci amba_set_drvdata(adev, pl022); 221862306a36Sopenharmony_ci status = devm_spi_register_controller(&adev->dev, host); 221962306a36Sopenharmony_ci if (status != 0) { 222062306a36Sopenharmony_ci dev_err_probe(&adev->dev, status, 222162306a36Sopenharmony_ci "problem registering spi host\n"); 222262306a36Sopenharmony_ci goto err_spi_register; 222362306a36Sopenharmony_ci } 222462306a36Sopenharmony_ci dev_dbg(dev, "probe succeeded\n"); 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci /* let runtime pm put suspend */ 222762306a36Sopenharmony_ci if (platform_info->autosuspend_delay > 0) { 222862306a36Sopenharmony_ci dev_info(&adev->dev, 222962306a36Sopenharmony_ci "will use autosuspend for runtime pm, delay %dms\n", 223062306a36Sopenharmony_ci platform_info->autosuspend_delay); 223162306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 223262306a36Sopenharmony_ci platform_info->autosuspend_delay); 223362306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 223462306a36Sopenharmony_ci } 223562306a36Sopenharmony_ci pm_runtime_put(dev); 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci return 0; 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci err_spi_register: 224062306a36Sopenharmony_ci if (platform_info->enable_dma) 224162306a36Sopenharmony_ci pl022_dma_remove(pl022); 224262306a36Sopenharmony_ci err_no_irq: 224362306a36Sopenharmony_ci clk_disable_unprepare(pl022->clk); 224462306a36Sopenharmony_ci err_no_clk_en: 224562306a36Sopenharmony_ci err_no_clk: 224662306a36Sopenharmony_ci err_no_ioremap: 224762306a36Sopenharmony_ci amba_release_regions(adev); 224862306a36Sopenharmony_ci err_no_ioregion: 224962306a36Sopenharmony_ci spi_controller_put(host); 225062306a36Sopenharmony_ci return status; 225162306a36Sopenharmony_ci} 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_cistatic void 225462306a36Sopenharmony_cipl022_remove(struct amba_device *adev) 225562306a36Sopenharmony_ci{ 225662306a36Sopenharmony_ci struct pl022 *pl022 = amba_get_drvdata(adev); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci if (!pl022) 225962306a36Sopenharmony_ci return; 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci /* 226262306a36Sopenharmony_ci * undo pm_runtime_put() in probe. I assume that we're not 226362306a36Sopenharmony_ci * accessing the primecell here. 226462306a36Sopenharmony_ci */ 226562306a36Sopenharmony_ci pm_runtime_get_noresume(&adev->dev); 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci load_ssp_default_config(pl022); 226862306a36Sopenharmony_ci if (pl022->host_info->enable_dma) 226962306a36Sopenharmony_ci pl022_dma_remove(pl022); 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci clk_disable_unprepare(pl022->clk); 227262306a36Sopenharmony_ci amba_release_regions(adev); 227362306a36Sopenharmony_ci tasklet_disable(&pl022->pump_transfers); 227462306a36Sopenharmony_ci} 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 227762306a36Sopenharmony_cistatic int pl022_suspend(struct device *dev) 227862306a36Sopenharmony_ci{ 227962306a36Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 228062306a36Sopenharmony_ci int ret; 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_ci ret = spi_controller_suspend(pl022->host); 228362306a36Sopenharmony_ci if (ret) 228462306a36Sopenharmony_ci return ret; 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci ret = pm_runtime_force_suspend(dev); 228762306a36Sopenharmony_ci if (ret) { 228862306a36Sopenharmony_ci spi_controller_resume(pl022->host); 228962306a36Sopenharmony_ci return ret; 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci dev_dbg(dev, "suspended\n"); 229562306a36Sopenharmony_ci return 0; 229662306a36Sopenharmony_ci} 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_cistatic int pl022_resume(struct device *dev) 229962306a36Sopenharmony_ci{ 230062306a36Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 230162306a36Sopenharmony_ci int ret; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci ret = pm_runtime_force_resume(dev); 230462306a36Sopenharmony_ci if (ret) 230562306a36Sopenharmony_ci dev_err(dev, "problem resuming\n"); 230662306a36Sopenharmony_ci 230762306a36Sopenharmony_ci /* Start the queue running */ 230862306a36Sopenharmony_ci ret = spi_controller_resume(pl022->host); 230962306a36Sopenharmony_ci if (!ret) 231062306a36Sopenharmony_ci dev_dbg(dev, "resumed\n"); 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci return ret; 231362306a36Sopenharmony_ci} 231462306a36Sopenharmony_ci#endif 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci#ifdef CONFIG_PM 231762306a36Sopenharmony_cistatic int pl022_runtime_suspend(struct device *dev) 231862306a36Sopenharmony_ci{ 231962306a36Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci clk_disable_unprepare(pl022->clk); 232262306a36Sopenharmony_ci pinctrl_pm_select_idle_state(dev); 232362306a36Sopenharmony_ci 232462306a36Sopenharmony_ci return 0; 232562306a36Sopenharmony_ci} 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_cistatic int pl022_runtime_resume(struct device *dev) 232862306a36Sopenharmony_ci{ 232962306a36Sopenharmony_ci struct pl022 *pl022 = dev_get_drvdata(dev); 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 233262306a36Sopenharmony_ci clk_prepare_enable(pl022->clk); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci return 0; 233562306a36Sopenharmony_ci} 233662306a36Sopenharmony_ci#endif 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_cistatic const struct dev_pm_ops pl022_dev_pm_ops = { 233962306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume) 234062306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL) 234162306a36Sopenharmony_ci}; 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_cistatic struct vendor_data vendor_arm = { 234462306a36Sopenharmony_ci .fifodepth = 8, 234562306a36Sopenharmony_ci .max_bpw = 16, 234662306a36Sopenharmony_ci .unidir = false, 234762306a36Sopenharmony_ci .extended_cr = false, 234862306a36Sopenharmony_ci .pl023 = false, 234962306a36Sopenharmony_ci .loopback = true, 235062306a36Sopenharmony_ci .internal_cs_ctrl = false, 235162306a36Sopenharmony_ci}; 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_cistatic struct vendor_data vendor_st = { 235462306a36Sopenharmony_ci .fifodepth = 32, 235562306a36Sopenharmony_ci .max_bpw = 32, 235662306a36Sopenharmony_ci .unidir = false, 235762306a36Sopenharmony_ci .extended_cr = true, 235862306a36Sopenharmony_ci .pl023 = false, 235962306a36Sopenharmony_ci .loopback = true, 236062306a36Sopenharmony_ci .internal_cs_ctrl = false, 236162306a36Sopenharmony_ci}; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_cistatic struct vendor_data vendor_st_pl023 = { 236462306a36Sopenharmony_ci .fifodepth = 32, 236562306a36Sopenharmony_ci .max_bpw = 32, 236662306a36Sopenharmony_ci .unidir = false, 236762306a36Sopenharmony_ci .extended_cr = true, 236862306a36Sopenharmony_ci .pl023 = true, 236962306a36Sopenharmony_ci .loopback = false, 237062306a36Sopenharmony_ci .internal_cs_ctrl = false, 237162306a36Sopenharmony_ci}; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_cistatic struct vendor_data vendor_lsi = { 237462306a36Sopenharmony_ci .fifodepth = 8, 237562306a36Sopenharmony_ci .max_bpw = 16, 237662306a36Sopenharmony_ci .unidir = false, 237762306a36Sopenharmony_ci .extended_cr = false, 237862306a36Sopenharmony_ci .pl023 = false, 237962306a36Sopenharmony_ci .loopback = true, 238062306a36Sopenharmony_ci .internal_cs_ctrl = true, 238162306a36Sopenharmony_ci}; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_cistatic const struct amba_id pl022_ids[] = { 238462306a36Sopenharmony_ci { 238562306a36Sopenharmony_ci /* 238662306a36Sopenharmony_ci * ARM PL022 variant, this has a 16bit wide 238762306a36Sopenharmony_ci * and 8 locations deep TX/RX FIFO 238862306a36Sopenharmony_ci */ 238962306a36Sopenharmony_ci .id = 0x00041022, 239062306a36Sopenharmony_ci .mask = 0x000fffff, 239162306a36Sopenharmony_ci .data = &vendor_arm, 239262306a36Sopenharmony_ci }, 239362306a36Sopenharmony_ci { 239462306a36Sopenharmony_ci /* 239562306a36Sopenharmony_ci * ST Micro derivative, this has 32bit wide 239662306a36Sopenharmony_ci * and 32 locations deep TX/RX FIFO 239762306a36Sopenharmony_ci */ 239862306a36Sopenharmony_ci .id = 0x01080022, 239962306a36Sopenharmony_ci .mask = 0xffffffff, 240062306a36Sopenharmony_ci .data = &vendor_st, 240162306a36Sopenharmony_ci }, 240262306a36Sopenharmony_ci { 240362306a36Sopenharmony_ci /* 240462306a36Sopenharmony_ci * ST-Ericsson derivative "PL023" (this is not 240562306a36Sopenharmony_ci * an official ARM number), this is a PL022 SSP block 240662306a36Sopenharmony_ci * stripped to SPI mode only, it has 32bit wide 240762306a36Sopenharmony_ci * and 32 locations deep TX/RX FIFO but no extended 240862306a36Sopenharmony_ci * CR0/CR1 register 240962306a36Sopenharmony_ci */ 241062306a36Sopenharmony_ci .id = 0x00080023, 241162306a36Sopenharmony_ci .mask = 0xffffffff, 241262306a36Sopenharmony_ci .data = &vendor_st_pl023, 241362306a36Sopenharmony_ci }, 241462306a36Sopenharmony_ci { 241562306a36Sopenharmony_ci /* 241662306a36Sopenharmony_ci * PL022 variant that has a chip select control register whih 241762306a36Sopenharmony_ci * allows control of 5 output signals nCS[0:4]. 241862306a36Sopenharmony_ci */ 241962306a36Sopenharmony_ci .id = 0x000b6022, 242062306a36Sopenharmony_ci .mask = 0x000fffff, 242162306a36Sopenharmony_ci .data = &vendor_lsi, 242262306a36Sopenharmony_ci }, 242362306a36Sopenharmony_ci { 0, 0 }, 242462306a36Sopenharmony_ci}; 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(amba, pl022_ids); 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_cistatic struct amba_driver pl022_driver = { 242962306a36Sopenharmony_ci .drv = { 243062306a36Sopenharmony_ci .name = "ssp-pl022", 243162306a36Sopenharmony_ci .pm = &pl022_dev_pm_ops, 243262306a36Sopenharmony_ci }, 243362306a36Sopenharmony_ci .id_table = pl022_ids, 243462306a36Sopenharmony_ci .probe = pl022_probe, 243562306a36Sopenharmony_ci .remove = pl022_remove, 243662306a36Sopenharmony_ci}; 243762306a36Sopenharmony_ci 243862306a36Sopenharmony_cistatic int __init pl022_init(void) 243962306a36Sopenharmony_ci{ 244062306a36Sopenharmony_ci return amba_driver_register(&pl022_driver); 244162306a36Sopenharmony_ci} 244262306a36Sopenharmony_cisubsys_initcall(pl022_init); 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_cistatic void __exit pl022_exit(void) 244562306a36Sopenharmony_ci{ 244662306a36Sopenharmony_ci amba_driver_unregister(&pl022_driver); 244762306a36Sopenharmony_ci} 244862306a36Sopenharmony_cimodule_exit(pl022_exit); 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ciMODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>"); 245162306a36Sopenharmony_ciMODULE_DESCRIPTION("PL022 SSP Controller Driver"); 245262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2453