2018-05-02 22:18:29 +03:00
// SPDX-License-Identifier: GPL-2.0+
//
// Freescale i.MX7ULP LPSPI driver
//
// Copyright 2016 Freescale Semiconductor, Inc.
2018-12-07 05:50:34 +03:00
// Copyright 2018 NXP Semiconductors
2016-11-22 16:52:17 +03:00
# include <linux/clk.h>
# include <linux/completion.h>
# include <linux/delay.h>
2019-03-06 09:30:45 +03:00
# include <linux/dmaengine.h>
# include <linux/dma-mapping.h>
2016-11-22 16:52:17 +03:00
# include <linux/err.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/irq.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_device.h>
2019-03-06 09:30:39 +03:00
# include <linux/pinctrl/consumer.h>
2016-11-22 16:52:17 +03:00
# include <linux/platform_device.h>
2022-04-14 19:22:37 +03:00
# include <linux/dma/imx-dma.h>
2019-03-06 09:30:39 +03:00
# include <linux/pm_runtime.h>
2016-11-22 16:52:17 +03:00
# include <linux/slab.h>
# include <linux/spi/spi.h>
# include <linux/spi/spi_bitbang.h>
# include <linux/types.h>
# define DRIVER_NAME "fsl_lpspi"
2019-03-06 09:30:39 +03:00
# define FSL_LPSPI_RPM_TIMEOUT 50 /* 50ms */
2019-03-06 09:30:45 +03:00
/* The maximum bytes that edma can transfer once.*/
# define FSL_LPSPI_MAX_EDMA_BYTES ((1 << 15) - 1)
2016-11-22 16:52:17 +03:00
/* i.MX7ULP LPSPI registers */
# define IMX7ULP_VERID 0x0
# define IMX7ULP_PARAM 0x4
# define IMX7ULP_CR 0x10
# define IMX7ULP_SR 0x14
# define IMX7ULP_IER 0x18
# define IMX7ULP_DER 0x1c
# define IMX7ULP_CFGR0 0x20
# define IMX7ULP_CFGR1 0x24
# define IMX7ULP_DMR0 0x30
# define IMX7ULP_DMR1 0x34
# define IMX7ULP_CCR 0x40
# define IMX7ULP_FCR 0x58
# define IMX7ULP_FSR 0x5c
# define IMX7ULP_TCR 0x60
# define IMX7ULP_TDR 0x64
# define IMX7ULP_RSR 0x70
# define IMX7ULP_RDR 0x74
/* General control register field define */
# define CR_RRF BIT(9)
# define CR_RTF BIT(8)
# define CR_RST BIT(1)
# define CR_MEN BIT(0)
2019-01-07 10:47:41 +03:00
# define SR_MBF BIT(24)
2016-11-22 16:52:17 +03:00
# define SR_TCF BIT(10)
2019-01-07 10:47:38 +03:00
# define SR_FCF BIT(9)
2016-11-22 16:52:17 +03:00
# define SR_RDF BIT(1)
# define SR_TDF BIT(0)
# define IER_TCIE BIT(10)
2019-01-07 10:47:38 +03:00
# define IER_FCIE BIT(9)
2016-11-22 16:52:17 +03:00
# define IER_RDIE BIT(1)
# define IER_TDIE BIT(0)
2019-03-06 09:30:45 +03:00
# define DER_RDDE BIT(1)
# define DER_TDDE BIT(0)
2016-11-22 16:52:17 +03:00
# define CFGR1_PCSCFG BIT(27)
2018-12-07 05:50:36 +03:00
# define CFGR1_PINCFG (BIT(24)|BIT(25))
2016-11-22 16:52:17 +03:00
# define CFGR1_PCSPOL BIT(8)
# define CFGR1_NOSTALL BIT(3)
# define CFGR1_MASTER BIT(0)
2019-03-21 12:57:12 +03:00
# define FSR_TXCOUNT (0xFF)
2016-11-22 16:52:17 +03:00
# define RSR_RXEMPTY BIT(1)
# define TCR_CPOL BIT(31)
# define TCR_CPHA BIT(30)
# define TCR_CONT BIT(21)
# define TCR_CONTC BIT(20)
# define TCR_RXMSK BIT(19)
# define TCR_TXMSK BIT(18)
struct lpspi_config {
u8 bpw ;
u8 chip_select ;
u8 prescale ;
u16 mode ;
u32 speed_hz ;
} ;
struct fsl_lpspi_data {
struct device * dev ;
void __iomem * base ;
2019-03-06 09:30:45 +03:00
unsigned long base_phys ;
2019-03-06 09:30:34 +03:00
struct clk * clk_ipg ;
struct clk * clk_per ;
2018-12-07 05:50:36 +03:00
bool is_slave ;
2020-07-27 06:14:48 +03:00
bool is_only_cs1 ;
2019-03-06 09:30:43 +03:00
bool is_first_byte ;
2016-11-22 16:52:17 +03:00
void * rx_buf ;
const void * tx_buf ;
void ( * tx ) ( struct fsl_lpspi_data * ) ;
void ( * rx ) ( struct fsl_lpspi_data * ) ;
u32 remain ;
2018-12-07 05:50:38 +03:00
u8 watermark ;
2016-11-22 16:52:17 +03:00
u8 txfifosize ;
u8 rxfifosize ;
struct lpspi_config config ;
struct completion xfer_done ;
2018-12-07 05:50:36 +03:00
bool slave_aborted ;
2019-03-06 09:30:43 +03:00
2019-03-06 09:30:45 +03:00
/* DMA */
bool usedma ;
struct completion dma_rx_completion ;
struct completion dma_tx_completion ;
2016-11-22 16:52:17 +03:00
} ;
static const struct of_device_id fsl_lpspi_dt_ids [ ] = {
{ . compatible = " fsl,imx7ulp-spi " , } ,
{ /* sentinel */ }
} ;
MODULE_DEVICE_TABLE ( of , fsl_lpspi_dt_ids ) ;
# define LPSPI_BUF_RX(type) \
static void fsl_lpspi_buf_rx_ # # type ( struct fsl_lpspi_data * fsl_lpspi ) \
{ \
unsigned int val = readl ( fsl_lpspi - > base + IMX7ULP_RDR ) ; \
\
if ( fsl_lpspi - > rx_buf ) { \
* ( type * ) fsl_lpspi - > rx_buf = val ; \
fsl_lpspi - > rx_buf + = sizeof ( type ) ; \
} \
}
# define LPSPI_BUF_TX(type) \
static void fsl_lpspi_buf_tx_ # # type ( struct fsl_lpspi_data * fsl_lpspi ) \
{ \
type val = 0 ; \
\
if ( fsl_lpspi - > tx_buf ) { \
val = * ( type * ) fsl_lpspi - > tx_buf ; \
fsl_lpspi - > tx_buf + = sizeof ( type ) ; \
} \
\
fsl_lpspi - > remain - = sizeof ( type ) ; \
writel ( val , fsl_lpspi - > base + IMX7ULP_TDR ) ; \
}
LPSPI_BUF_RX ( u8 )
LPSPI_BUF_TX ( u8 )
LPSPI_BUF_RX ( u16 )
LPSPI_BUF_TX ( u16 )
LPSPI_BUF_RX ( u32 )
LPSPI_BUF_TX ( u32 )
static void fsl_lpspi_intctrl ( struct fsl_lpspi_data * fsl_lpspi ,
unsigned int enable )
{
writel ( enable , fsl_lpspi - > base + IMX7ULP_IER ) ;
}
2019-03-06 09:30:45 +03:00
static int fsl_lpspi_bytes_per_word ( const int bpw )
{
return DIV_ROUND_UP ( bpw , BITS_PER_BYTE ) ;
}
static bool fsl_lpspi_can_dma ( struct spi_controller * controller ,
struct spi_device * spi ,
struct spi_transfer * transfer )
{
unsigned int bytes_per_word ;
if ( ! controller - > dma_rx )
return false ;
bytes_per_word = fsl_lpspi_bytes_per_word ( transfer - > bits_per_word ) ;
2020-04-07 15:55:57 +03:00
switch ( bytes_per_word ) {
case 1 :
case 2 :
case 4 :
break ;
default :
return false ;
2019-03-06 09:30:45 +03:00
}
return true ;
}
2018-12-07 05:50:34 +03:00
static int lpspi_prepare_xfer_hardware ( struct spi_controller * controller )
2016-11-22 16:52:17 +03:00
{
2018-12-07 05:50:34 +03:00
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( controller ) ;
2019-03-06 09:30:34 +03:00
int ret ;
2021-04-09 12:54:30 +03:00
ret = pm_runtime_resume_and_get ( fsl_lpspi - > dev ) ;
2019-03-06 09:30:39 +03:00
if ( ret < 0 ) {
dev_err ( fsl_lpspi - > dev , " failed to enable clock \n " ) ;
2019-03-06 09:30:34 +03:00
return ret ;
}
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:34 +03:00
return 0 ;
2016-11-22 16:52:17 +03:00
}
2018-12-07 05:50:34 +03:00
static int lpspi_unprepare_xfer_hardware ( struct spi_controller * controller )
2016-11-22 16:52:17 +03:00
{
2018-12-07 05:50:34 +03:00
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( controller ) ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:39 +03:00
pm_runtime_mark_last_busy ( fsl_lpspi - > dev ) ;
pm_runtime_put_autosuspend ( fsl_lpspi - > dev ) ;
2016-11-22 16:52:17 +03:00
return 0 ;
}
static void fsl_lpspi_write_tx_fifo ( struct fsl_lpspi_data * fsl_lpspi )
{
u8 txfifo_cnt ;
2019-01-07 10:47:38 +03:00
u32 temp ;
2016-11-22 16:52:17 +03:00
txfifo_cnt = readl ( fsl_lpspi - > base + IMX7ULP_FSR ) & 0xff ;
while ( txfifo_cnt < fsl_lpspi - > txfifosize ) {
if ( ! fsl_lpspi - > remain )
break ;
fsl_lpspi - > tx ( fsl_lpspi ) ;
txfifo_cnt + + ;
}
2019-01-07 10:47:38 +03:00
if ( txfifo_cnt < fsl_lpspi - > txfifosize ) {
if ( ! fsl_lpspi - > is_slave ) {
temp = readl ( fsl_lpspi - > base + IMX7ULP_TCR ) ;
temp & = ~ TCR_CONTC ;
writel ( temp , fsl_lpspi - > base + IMX7ULP_TCR ) ;
}
fsl_lpspi_intctrl ( fsl_lpspi , IER_FCIE ) ;
} else
2016-11-22 16:52:17 +03:00
fsl_lpspi_intctrl ( fsl_lpspi , IER_TDIE ) ;
}
static void fsl_lpspi_read_rx_fifo ( struct fsl_lpspi_data * fsl_lpspi )
{
while ( ! ( readl ( fsl_lpspi - > base + IMX7ULP_RSR ) & RSR_RXEMPTY ) )
fsl_lpspi - > rx ( fsl_lpspi ) ;
}
2019-03-06 09:30:43 +03:00
static void fsl_lpspi_set_cmd ( struct fsl_lpspi_data * fsl_lpspi )
2016-11-22 16:52:17 +03:00
{
u32 temp = 0 ;
temp | = fsl_lpspi - > config . bpw - 1 ;
2016-11-24 14:04:43 +03:00
temp | = ( fsl_lpspi - > config . mode & 0x3 ) < < 30 ;
2020-07-27 06:14:48 +03:00
temp | = ( fsl_lpspi - > config . chip_select & 0x3 ) < < 24 ;
2018-12-07 05:50:36 +03:00
if ( ! fsl_lpspi - > is_slave ) {
temp | = fsl_lpspi - > config . prescale < < 27 ;
/*
* Set TCR_CONT will keep SS asserted after current transfer .
* For the first transfer , clear TCR_CONTC to assert SS .
* For subsequent transfer , set TCR_CONTC to keep SS asserted .
*/
2019-03-06 09:30:45 +03:00
if ( ! fsl_lpspi - > usedma ) {
temp | = TCR_CONT ;
if ( fsl_lpspi - > is_first_byte )
temp & = ~ TCR_CONTC ;
else
temp | = TCR_CONTC ;
}
2018-12-07 05:50:36 +03:00
}
2016-11-22 16:52:17 +03:00
writel ( temp , fsl_lpspi - > base + IMX7ULP_TCR ) ;
dev_dbg ( fsl_lpspi - > dev , " TCR=0x%x \n " , temp ) ;
}
static void fsl_lpspi_set_watermark ( struct fsl_lpspi_data * fsl_lpspi )
{
u32 temp ;
2019-03-06 09:30:45 +03:00
if ( ! fsl_lpspi - > usedma )
temp = fsl_lpspi - > watermark > > 1 |
( fsl_lpspi - > watermark > > 1 ) < < 16 ;
else
temp = fsl_lpspi - > watermark > > 1 ;
2016-11-22 16:52:17 +03:00
writel ( temp , fsl_lpspi - > base + IMX7ULP_FCR ) ;
dev_dbg ( fsl_lpspi - > dev , " FCR=0x%x \n " , temp ) ;
}
static int fsl_lpspi_set_bitrate ( struct fsl_lpspi_data * fsl_lpspi )
{
struct lpspi_config config = fsl_lpspi - > config ;
unsigned int perclk_rate , scldiv ;
u8 prescale ;
2019-03-06 09:30:34 +03:00
perclk_rate = clk_get_rate ( fsl_lpspi - > clk_per ) ;
2019-03-06 09:30:41 +03:00
if ( config . speed_hz > perclk_rate / 2 ) {
dev_err ( fsl_lpspi - > dev ,
" per-clk should be at least two times of transfer speed " ) ;
return - EINVAL ;
}
2016-11-22 16:52:17 +03:00
for ( prescale = 0 ; prescale < 8 ; prescale + + ) {
2020-02-20 17:11:48 +03:00
scldiv = perclk_rate / config . speed_hz / ( 1 < < prescale ) - 2 ;
2016-11-22 16:52:17 +03:00
if ( scldiv < 256 ) {
fsl_lpspi - > config . prescale = prescale ;
break ;
}
}
2020-02-20 17:11:48 +03:00
if ( scldiv > = 256 )
2016-11-22 16:52:17 +03:00
return - EINVAL ;
2018-12-07 05:50:38 +03:00
writel ( scldiv | ( scldiv < < 8 ) | ( ( scldiv > > 1 ) < < 16 ) ,
fsl_lpspi - > base + IMX7ULP_CCR ) ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:49 +03:00
dev_dbg ( fsl_lpspi - > dev , " perclk=%d, speed=%d, prescale=%d, scldiv=%d \n " ,
2016-11-22 16:52:17 +03:00
perclk_rate , config . speed_hz , prescale , scldiv ) ;
return 0 ;
}
2019-03-06 09:30:45 +03:00
static int fsl_lpspi_dma_configure ( struct spi_controller * controller )
{
int ret ;
enum dma_slave_buswidth buswidth ;
struct dma_slave_config rx = { } , tx = { } ;
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( controller ) ;
switch ( fsl_lpspi_bytes_per_word ( fsl_lpspi - > config . bpw ) ) {
case 4 :
buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES ;
break ;
case 2 :
buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES ;
break ;
case 1 :
buswidth = DMA_SLAVE_BUSWIDTH_1_BYTE ;
break ;
default :
return - EINVAL ;
}
tx . direction = DMA_MEM_TO_DEV ;
tx . dst_addr = fsl_lpspi - > base_phys + IMX7ULP_TDR ;
tx . dst_addr_width = buswidth ;
tx . dst_maxburst = 1 ;
ret = dmaengine_slave_config ( controller - > dma_tx , & tx ) ;
if ( ret ) {
dev_err ( fsl_lpspi - > dev , " TX dma configuration failed with %d \n " ,
ret ) ;
return ret ;
}
rx . direction = DMA_DEV_TO_MEM ;
rx . src_addr = fsl_lpspi - > base_phys + IMX7ULP_RDR ;
rx . src_addr_width = buswidth ;
rx . src_maxburst = 1 ;
ret = dmaengine_slave_config ( controller - > dma_rx , & rx ) ;
if ( ret ) {
dev_err ( fsl_lpspi - > dev , " RX dma configuration failed with %d \n " ,
ret ) ;
return ret ;
}
return 0 ;
}
2016-11-22 16:52:17 +03:00
static int fsl_lpspi_config ( struct fsl_lpspi_data * fsl_lpspi )
{
u32 temp ;
int ret ;
2018-12-07 05:50:36 +03:00
if ( ! fsl_lpspi - > is_slave ) {
ret = fsl_lpspi_set_bitrate ( fsl_lpspi ) ;
if ( ret )
return ret ;
}
2016-11-22 16:52:17 +03:00
fsl_lpspi_set_watermark ( fsl_lpspi ) ;
2018-12-07 05:50:36 +03:00
if ( ! fsl_lpspi - > is_slave )
temp = CFGR1_MASTER ;
else
temp = CFGR1_PINCFG ;
2016-11-22 16:52:17 +03:00
if ( fsl_lpspi - > config . mode & SPI_CS_HIGH )
temp | = CFGR1_PCSPOL ;
writel ( temp , fsl_lpspi - > base + IMX7ULP_CFGR1 ) ;
temp = readl ( fsl_lpspi - > base + IMX7ULP_CR ) ;
temp | = CR_RRF | CR_RTF | CR_MEN ;
writel ( temp , fsl_lpspi - > base + IMX7ULP_CR ) ;
2019-03-06 09:30:45 +03:00
temp = 0 ;
if ( fsl_lpspi - > usedma )
temp = DER_TDDE | DER_RDDE ;
writel ( temp , fsl_lpspi - > base + IMX7ULP_DER ) ;
2016-11-22 16:52:17 +03:00
return 0 ;
}
2019-03-06 09:30:45 +03:00
static int fsl_lpspi_setup_transfer ( struct spi_controller * controller ,
struct spi_device * spi ,
2016-11-22 16:52:17 +03:00
struct spi_transfer * t )
{
2018-12-07 05:50:34 +03:00
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( spi - > controller ) ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:47 +03:00
if ( t = = NULL )
return - EINVAL ;
2016-11-22 16:52:17 +03:00
fsl_lpspi - > config . mode = spi - > mode ;
2019-03-06 09:30:47 +03:00
fsl_lpspi - > config . bpw = t - > bits_per_word ;
fsl_lpspi - > config . speed_hz = t - > speed_hz ;
2020-07-27 06:14:48 +03:00
if ( fsl_lpspi - > is_only_cs1 )
fsl_lpspi - > config . chip_select = 1 ;
else
fsl_lpspi - > config . chip_select = spi - > chip_select ;
2016-11-22 16:52:17 +03:00
if ( ! fsl_lpspi - > config . speed_hz )
fsl_lpspi - > config . speed_hz = spi - > max_speed_hz ;
if ( ! fsl_lpspi - > config . bpw )
fsl_lpspi - > config . bpw = spi - > bits_per_word ;
/* Initialize the functions for transfer */
if ( fsl_lpspi - > config . bpw < = 8 ) {
fsl_lpspi - > rx = fsl_lpspi_buf_rx_u8 ;
fsl_lpspi - > tx = fsl_lpspi_buf_tx_u8 ;
} else if ( fsl_lpspi - > config . bpw < = 16 ) {
fsl_lpspi - > rx = fsl_lpspi_buf_rx_u16 ;
fsl_lpspi - > tx = fsl_lpspi_buf_tx_u16 ;
} else {
fsl_lpspi - > rx = fsl_lpspi_buf_rx_u32 ;
fsl_lpspi - > tx = fsl_lpspi_buf_tx_u32 ;
}
2018-12-07 05:50:38 +03:00
if ( t - > len < = fsl_lpspi - > txfifosize )
fsl_lpspi - > watermark = t - > len ;
else
fsl_lpspi - > watermark = fsl_lpspi - > txfifosize ;
2019-03-06 09:30:45 +03:00
if ( fsl_lpspi_can_dma ( controller , spi , t ) )
2019-12-24 06:52:04 +03:00
fsl_lpspi - > usedma = true ;
2019-03-06 09:30:45 +03:00
else
2019-12-24 06:52:04 +03:00
fsl_lpspi - > usedma = false ;
2019-03-06 09:30:45 +03:00
2019-03-06 09:30:41 +03:00
return fsl_lpspi_config ( fsl_lpspi ) ;
2016-11-22 16:52:17 +03:00
}
2018-12-07 05:50:36 +03:00
static int fsl_lpspi_slave_abort ( struct spi_controller * controller )
{
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( controller ) ;
fsl_lpspi - > slave_aborted = true ;
2019-04-02 15:45:53 +03:00
if ( ! fsl_lpspi - > usedma )
complete ( & fsl_lpspi - > xfer_done ) ;
else {
complete ( & fsl_lpspi - > dma_tx_completion ) ;
complete ( & fsl_lpspi - > dma_rx_completion ) ;
}
2018-12-07 05:50:36 +03:00
return 0 ;
}
static int fsl_lpspi_wait_for_completion ( struct spi_controller * controller )
{
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( controller ) ;
if ( fsl_lpspi - > is_slave ) {
if ( wait_for_completion_interruptible ( & fsl_lpspi - > xfer_done ) | |
fsl_lpspi - > slave_aborted ) {
dev_dbg ( fsl_lpspi - > dev , " interrupted \n " ) ;
return - EINTR ;
}
} else {
if ( ! wait_for_completion_timeout ( & fsl_lpspi - > xfer_done , HZ ) ) {
dev_dbg ( fsl_lpspi - > dev , " wait for completion timeout \n " ) ;
return - ETIMEDOUT ;
}
}
return 0 ;
}
2019-01-07 10:47:43 +03:00
static int fsl_lpspi_reset ( struct fsl_lpspi_data * fsl_lpspi )
{
u32 temp ;
2019-03-06 09:30:45 +03:00
if ( ! fsl_lpspi - > usedma ) {
/* Disable all interrupt */
fsl_lpspi_intctrl ( fsl_lpspi , 0 ) ;
}
2019-01-07 10:47:43 +03:00
/* W1C for all flags in SR */
temp = 0x3F < < 8 ;
writel ( temp , fsl_lpspi - > base + IMX7ULP_SR ) ;
/* Clear FIFO and disable module */
temp = CR_RRF | CR_RTF ;
writel ( temp , fsl_lpspi - > base + IMX7ULP_CR ) ;
return 0 ;
}
2019-03-06 09:30:45 +03:00
static void fsl_lpspi_dma_rx_callback ( void * cookie )
{
struct fsl_lpspi_data * fsl_lpspi = ( struct fsl_lpspi_data * ) cookie ;
complete ( & fsl_lpspi - > dma_rx_completion ) ;
}
static void fsl_lpspi_dma_tx_callback ( void * cookie )
{
struct fsl_lpspi_data * fsl_lpspi = ( struct fsl_lpspi_data * ) cookie ;
complete ( & fsl_lpspi - > dma_tx_completion ) ;
}
static int fsl_lpspi_calculate_timeout ( struct fsl_lpspi_data * fsl_lpspi ,
int size )
{
unsigned long timeout = 0 ;
/* Time with actual data transfer and CS change delay related to HW */
timeout = ( 8 + 4 ) * size / fsl_lpspi - > config . speed_hz ;
/* Add extra second for scheduler related activities */
timeout + = 1 ;
/* Double calculated timeout */
return msecs_to_jiffies ( 2 * timeout * MSEC_PER_SEC ) ;
}
static int fsl_lpspi_dma_transfer ( struct spi_controller * controller ,
struct fsl_lpspi_data * fsl_lpspi ,
struct spi_transfer * transfer )
{
struct dma_async_tx_descriptor * desc_tx , * desc_rx ;
unsigned long transfer_timeout ;
unsigned long timeout ;
struct sg_table * tx = & transfer - > tx_sg , * rx = & transfer - > rx_sg ;
int ret ;
ret = fsl_lpspi_dma_configure ( controller ) ;
if ( ret )
return ret ;
desc_rx = dmaengine_prep_slave_sg ( controller - > dma_rx ,
rx - > sgl , rx - > nents , DMA_DEV_TO_MEM ,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK ) ;
if ( ! desc_rx )
return - EINVAL ;
desc_rx - > callback = fsl_lpspi_dma_rx_callback ;
desc_rx - > callback_param = ( void * ) fsl_lpspi ;
dmaengine_submit ( desc_rx ) ;
reinit_completion ( & fsl_lpspi - > dma_rx_completion ) ;
dma_async_issue_pending ( controller - > dma_rx ) ;
desc_tx = dmaengine_prep_slave_sg ( controller - > dma_tx ,
tx - > sgl , tx - > nents , DMA_MEM_TO_DEV ,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK ) ;
if ( ! desc_tx ) {
dmaengine_terminate_all ( controller - > dma_tx ) ;
return - EINVAL ;
}
desc_tx - > callback = fsl_lpspi_dma_tx_callback ;
desc_tx - > callback_param = ( void * ) fsl_lpspi ;
dmaengine_submit ( desc_tx ) ;
reinit_completion ( & fsl_lpspi - > dma_tx_completion ) ;
dma_async_issue_pending ( controller - > dma_tx ) ;
fsl_lpspi - > slave_aborted = false ;
if ( ! fsl_lpspi - > is_slave ) {
transfer_timeout = fsl_lpspi_calculate_timeout ( fsl_lpspi ,
transfer - > len ) ;
/* Wait eDMA to finish the data transfer.*/
timeout = wait_for_completion_timeout ( & fsl_lpspi - > dma_tx_completion ,
transfer_timeout ) ;
if ( ! timeout ) {
dev_err ( fsl_lpspi - > dev , " I/O Error in DMA TX \n " ) ;
dmaengine_terminate_all ( controller - > dma_tx ) ;
dmaengine_terminate_all ( controller - > dma_rx ) ;
fsl_lpspi_reset ( fsl_lpspi ) ;
return - ETIMEDOUT ;
}
timeout = wait_for_completion_timeout ( & fsl_lpspi - > dma_rx_completion ,
transfer_timeout ) ;
if ( ! timeout ) {
dev_err ( fsl_lpspi - > dev , " I/O Error in DMA RX \n " ) ;
dmaengine_terminate_all ( controller - > dma_tx ) ;
dmaengine_terminate_all ( controller - > dma_rx ) ;
fsl_lpspi_reset ( fsl_lpspi ) ;
return - ETIMEDOUT ;
}
} else {
if ( wait_for_completion_interruptible ( & fsl_lpspi - > dma_tx_completion ) | |
fsl_lpspi - > slave_aborted ) {
dev_dbg ( fsl_lpspi - > dev ,
" I/O Error in DMA TX interrupted \n " ) ;
dmaengine_terminate_all ( controller - > dma_tx ) ;
dmaengine_terminate_all ( controller - > dma_rx ) ;
fsl_lpspi_reset ( fsl_lpspi ) ;
return - EINTR ;
}
if ( wait_for_completion_interruptible ( & fsl_lpspi - > dma_rx_completion ) | |
fsl_lpspi - > slave_aborted ) {
dev_dbg ( fsl_lpspi - > dev ,
" I/O Error in DMA RX interrupted \n " ) ;
dmaengine_terminate_all ( controller - > dma_tx ) ;
dmaengine_terminate_all ( controller - > dma_rx ) ;
fsl_lpspi_reset ( fsl_lpspi ) ;
return - EINTR ;
}
}
fsl_lpspi_reset ( fsl_lpspi ) ;
return 0 ;
}
static void fsl_lpspi_dma_exit ( struct spi_controller * controller )
{
if ( controller - > dma_rx ) {
dma_release_channel ( controller - > dma_rx ) ;
controller - > dma_rx = NULL ;
}
if ( controller - > dma_tx ) {
dma_release_channel ( controller - > dma_tx ) ;
controller - > dma_tx = NULL ;
}
}
static int fsl_lpspi_dma_init ( struct device * dev ,
struct fsl_lpspi_data * fsl_lpspi ,
struct spi_controller * controller )
{
int ret ;
/* Prepare for TX DMA: */
2019-11-13 12:42:50 +03:00
controller - > dma_tx = dma_request_chan ( dev , " tx " ) ;
2019-03-06 09:30:45 +03:00
if ( IS_ERR ( controller - > dma_tx ) ) {
ret = PTR_ERR ( controller - > dma_tx ) ;
dev_dbg ( dev , " can't get the TX DMA channel, error %d! \n " , ret ) ;
controller - > dma_tx = NULL ;
goto err ;
}
/* Prepare for RX DMA: */
2019-11-13 12:42:50 +03:00
controller - > dma_rx = dma_request_chan ( dev , " rx " ) ;
2019-03-06 09:30:45 +03:00
if ( IS_ERR ( controller - > dma_rx ) ) {
ret = PTR_ERR ( controller - > dma_rx ) ;
dev_dbg ( dev , " can't get the RX DMA channel, error %d \n " , ret ) ;
controller - > dma_rx = NULL ;
goto err ;
}
init_completion ( & fsl_lpspi - > dma_rx_completion ) ;
init_completion ( & fsl_lpspi - > dma_tx_completion ) ;
controller - > can_dma = fsl_lpspi_can_dma ;
controller - > max_dma_len = FSL_LPSPI_MAX_EDMA_BYTES ;
return 0 ;
err :
fsl_lpspi_dma_exit ( controller ) ;
return ret ;
}
2019-03-06 09:30:43 +03:00
static int fsl_lpspi_pio_transfer ( struct spi_controller * controller ,
2016-11-22 16:52:17 +03:00
struct spi_transfer * t )
{
2018-12-07 05:50:34 +03:00
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( controller ) ;
2016-11-22 16:52:17 +03:00
int ret ;
fsl_lpspi - > tx_buf = t - > tx_buf ;
fsl_lpspi - > rx_buf = t - > rx_buf ;
fsl_lpspi - > remain = t - > len ;
reinit_completion ( & fsl_lpspi - > xfer_done ) ;
2018-12-07 05:50:36 +03:00
fsl_lpspi - > slave_aborted = false ;
2016-11-22 16:52:17 +03:00
fsl_lpspi_write_tx_fifo ( fsl_lpspi ) ;
2016-11-28 06:02:59 +03:00
2018-12-07 05:50:36 +03:00
ret = fsl_lpspi_wait_for_completion ( controller ) ;
if ( ret )
return ret ;
2016-11-22 16:52:17 +03:00
2019-01-07 10:47:43 +03:00
fsl_lpspi_reset ( fsl_lpspi ) ;
2016-12-02 06:50:01 +03:00
return 0 ;
2016-11-22 16:52:17 +03:00
}
2019-03-06 09:30:43 +03:00
static int fsl_lpspi_transfer_one ( struct spi_controller * controller ,
struct spi_device * spi ,
struct spi_transfer * t )
2016-11-22 16:52:17 +03:00
{
2018-12-07 05:50:34 +03:00
struct fsl_lpspi_data * fsl_lpspi =
2019-03-06 09:30:43 +03:00
spi_controller_get_devdata ( controller ) ;
int ret ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:43 +03:00
fsl_lpspi - > is_first_byte = true ;
2019-03-06 09:30:45 +03:00
ret = fsl_lpspi_setup_transfer ( controller , spi , t ) ;
2019-03-06 09:30:43 +03:00
if ( ret < 0 )
return ret ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:43 +03:00
fsl_lpspi_set_cmd ( fsl_lpspi ) ;
fsl_lpspi - > is_first_byte = false ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:45 +03:00
if ( fsl_lpspi - > usedma )
ret = fsl_lpspi_dma_transfer ( controller , fsl_lpspi , t ) ;
else
ret = fsl_lpspi_pio_transfer ( controller , t ) ;
2019-03-06 09:30:43 +03:00
if ( ret < 0 )
return ret ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:43 +03:00
return 0 ;
2016-11-22 16:52:17 +03:00
}
static irqreturn_t fsl_lpspi_isr ( int irq , void * dev_id )
{
2019-01-07 10:47:38 +03:00
u32 temp_SR , temp_IER ;
2016-11-22 16:52:17 +03:00
struct fsl_lpspi_data * fsl_lpspi = dev_id ;
2019-01-07 10:47:38 +03:00
temp_IER = readl ( fsl_lpspi - > base + IMX7ULP_IER ) ;
2016-11-22 16:52:17 +03:00
fsl_lpspi_intctrl ( fsl_lpspi , 0 ) ;
2019-01-07 10:47:38 +03:00
temp_SR = readl ( fsl_lpspi - > base + IMX7ULP_SR ) ;
2016-11-22 16:52:17 +03:00
fsl_lpspi_read_rx_fifo ( fsl_lpspi ) ;
2019-01-07 10:47:38 +03:00
if ( ( temp_SR & SR_TDF ) & & ( temp_IER & IER_TDIE ) ) {
2016-11-22 16:52:17 +03:00
fsl_lpspi_write_tx_fifo ( fsl_lpspi ) ;
2019-01-07 10:47:38 +03:00
return IRQ_HANDLED ;
}
2016-11-22 16:52:17 +03:00
2019-01-07 10:47:41 +03:00
if ( temp_SR & SR_MBF | |
2019-03-21 12:57:12 +03:00
readl ( fsl_lpspi - > base + IMX7ULP_FSR ) & FSR_TXCOUNT ) {
2019-01-07 10:47:41 +03:00
writel ( SR_FCF , fsl_lpspi - > base + IMX7ULP_SR ) ;
fsl_lpspi_intctrl ( fsl_lpspi , IER_FCIE ) ;
return IRQ_HANDLED ;
}
2019-01-07 10:47:38 +03:00
if ( temp_SR & SR_FCF & & ( temp_IER & IER_FCIE ) ) {
writel ( SR_FCF , fsl_lpspi - > base + IMX7ULP_SR ) ;
2019-09-26 14:37:01 +03:00
complete ( & fsl_lpspi - > xfer_done ) ;
2016-11-22 16:52:17 +03:00
return IRQ_HANDLED ;
}
return IRQ_NONE ;
}
2019-04-07 17:58:16 +03:00
# ifdef CONFIG_PM
2019-03-19 04:46:33 +03:00
static int fsl_lpspi_runtime_resume ( struct device * dev )
2019-03-06 09:30:39 +03:00
{
2019-04-07 17:58:15 +03:00
struct spi_controller * controller = dev_get_drvdata ( dev ) ;
struct fsl_lpspi_data * fsl_lpspi ;
2019-03-06 09:30:39 +03:00
int ret ;
2019-04-07 17:58:15 +03:00
fsl_lpspi = spi_controller_get_devdata ( controller ) ;
2019-03-06 09:30:39 +03:00
ret = clk_prepare_enable ( fsl_lpspi - > clk_per ) ;
if ( ret )
return ret ;
ret = clk_prepare_enable ( fsl_lpspi - > clk_ipg ) ;
if ( ret ) {
clk_disable_unprepare ( fsl_lpspi - > clk_per ) ;
return ret ;
}
return 0 ;
}
2019-03-19 04:46:33 +03:00
static int fsl_lpspi_runtime_suspend ( struct device * dev )
2019-03-06 09:30:39 +03:00
{
2019-04-07 17:58:15 +03:00
struct spi_controller * controller = dev_get_drvdata ( dev ) ;
struct fsl_lpspi_data * fsl_lpspi ;
fsl_lpspi = spi_controller_get_devdata ( controller ) ;
2019-03-06 09:30:39 +03:00
clk_disable_unprepare ( fsl_lpspi - > clk_per ) ;
clk_disable_unprepare ( fsl_lpspi - > clk_ipg ) ;
return 0 ;
}
2019-04-07 17:58:16 +03:00
# endif
2019-03-06 09:30:39 +03:00
static int fsl_lpspi_init_rpm ( struct fsl_lpspi_data * fsl_lpspi )
{
struct device * dev = fsl_lpspi - > dev ;
pm_runtime_enable ( dev ) ;
pm_runtime_set_autosuspend_delay ( dev , FSL_LPSPI_RPM_TIMEOUT ) ;
pm_runtime_use_autosuspend ( dev ) ;
return 0 ;
}
2016-11-22 16:52:17 +03:00
static int fsl_lpspi_probe ( struct platform_device * pdev )
{
struct fsl_lpspi_data * fsl_lpspi ;
2018-12-07 05:50:34 +03:00
struct spi_controller * controller ;
2016-11-22 16:52:17 +03:00
struct resource * res ;
2020-06-25 23:02:52 +03:00
int ret , irq ;
2016-11-28 06:03:00 +03:00
u32 temp ;
2019-04-07 17:58:17 +03:00
bool is_slave ;
2016-11-22 16:52:17 +03:00
2019-04-07 17:58:17 +03:00
is_slave = of_property_read_bool ( ( & pdev - > dev ) - > of_node , " spi-slave " ) ;
if ( is_slave )
2018-12-07 05:50:36 +03:00
controller = spi_alloc_slave ( & pdev - > dev ,
sizeof ( struct fsl_lpspi_data ) ) ;
else
controller = spi_alloc_master ( & pdev - > dev ,
2018-12-07 05:50:34 +03:00
sizeof ( struct fsl_lpspi_data ) ) ;
2018-12-07 05:50:36 +03:00
2018-12-07 05:50:34 +03:00
if ( ! controller )
2016-11-22 16:52:17 +03:00
return - ENOMEM ;
2018-12-07 05:50:34 +03:00
platform_set_drvdata ( pdev , controller ) ;
2016-11-22 16:52:17 +03:00
2018-12-07 05:50:34 +03:00
fsl_lpspi = spi_controller_get_devdata ( controller ) ;
2016-11-22 16:52:17 +03:00
fsl_lpspi - > dev = & pdev - > dev ;
2019-04-07 17:58:17 +03:00
fsl_lpspi - > is_slave = is_slave ;
2020-07-27 06:14:48 +03:00
fsl_lpspi - > is_only_cs1 = of_property_read_bool ( ( & pdev - > dev ) - > of_node ,
" fsl,spi-only-use-cs1-sel " ) ;
2016-11-22 16:52:17 +03:00
2019-12-04 17:13:33 +03:00
controller - > bits_per_word_mask = SPI_BPW_RANGE_MASK ( 8 , 32 ) ;
controller - > transfer_one = fsl_lpspi_transfer_one ;
controller - > prepare_transfer_hardware = lpspi_prepare_xfer_hardware ;
controller - > unprepare_transfer_hardware = lpspi_unprepare_xfer_hardware ;
controller - > mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH ;
controller - > flags = SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX ;
controller - > dev . of_node = pdev - > dev . of_node ;
controller - > bus_num = pdev - > id ;
controller - > slave_abort = fsl_lpspi_slave_abort ;
2020-06-25 23:02:52 +03:00
if ( ! fsl_lpspi - > is_slave )
controller - > use_gpio_descriptors = true ;
2019-12-04 17:13:33 +03:00
2016-11-22 16:52:17 +03:00
init_completion ( & fsl_lpspi - > xfer_done ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
fsl_lpspi - > base = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( fsl_lpspi - > base ) ) {
ret = PTR_ERR ( fsl_lpspi - > base ) ;
2018-12-07 05:50:34 +03:00
goto out_controller_put ;
2016-11-22 16:52:17 +03:00
}
2019-03-06 09:30:45 +03:00
fsl_lpspi - > base_phys = res - > start ;
2016-11-22 16:52:17 +03:00
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
ret = irq ;
2018-12-07 05:50:34 +03:00
goto out_controller_put ;
2016-11-22 16:52:17 +03:00
}
ret = devm_request_irq ( & pdev - > dev , irq , fsl_lpspi_isr , 0 ,
dev_name ( & pdev - > dev ) , fsl_lpspi ) ;
if ( ret ) {
dev_err ( & pdev - > dev , " can't get irq%d: %d \n " , irq , ret ) ;
2018-12-07 05:50:34 +03:00
goto out_controller_put ;
2016-11-22 16:52:17 +03:00
}
2019-03-06 09:30:34 +03:00
fsl_lpspi - > clk_per = devm_clk_get ( & pdev - > dev , " per " ) ;
if ( IS_ERR ( fsl_lpspi - > clk_per ) ) {
ret = PTR_ERR ( fsl_lpspi - > clk_per ) ;
goto out_controller_put ;
}
fsl_lpspi - > clk_ipg = devm_clk_get ( & pdev - > dev , " ipg " ) ;
if ( IS_ERR ( fsl_lpspi - > clk_ipg ) ) {
ret = PTR_ERR ( fsl_lpspi - > clk_ipg ) ;
goto out_controller_put ;
}
2019-03-06 09:30:39 +03:00
/* enable the clock */
ret = fsl_lpspi_init_rpm ( fsl_lpspi ) ;
if ( ret )
2018-12-07 05:50:34 +03:00
goto out_controller_put ;
2016-11-22 16:52:17 +03:00
2019-03-06 09:30:39 +03:00
ret = pm_runtime_get_sync ( fsl_lpspi - > dev ) ;
if ( ret < 0 ) {
dev_err ( fsl_lpspi - > dev , " failed to enable clock \n " ) ;
2020-05-23 16:38:59 +03:00
goto out_pm_get ;
2016-11-28 06:03:00 +03:00
}
temp = readl ( fsl_lpspi - > base + IMX7ULP_PARAM ) ;
fsl_lpspi - > txfifosize = 1 < < ( temp & 0x0f ) ;
fsl_lpspi - > rxfifosize = 1 < < ( ( temp > > 8 ) & 0x0f ) ;
2019-03-06 09:30:45 +03:00
ret = fsl_lpspi_dma_init ( & pdev - > dev , fsl_lpspi , controller ) ;
if ( ret = = - EPROBE_DEFER )
2020-05-23 16:38:59 +03:00
goto out_pm_get ;
2019-03-06 09:30:45 +03:00
if ( ret < 0 )
dev_err ( & pdev - > dev , " dma setup error %d, use pio \n " , ret ) ;
2020-07-27 06:14:46 +03:00
ret = devm_spi_register_controller ( & pdev - > dev , controller ) ;
if ( ret < 0 ) {
2021-11-08 17:55:23 +03:00
dev_err_probe ( & pdev - > dev , ret , " spi_register_controller error: %i \n " , ret ) ;
2021-11-09 13:31:34 +03:00
goto free_dma ;
2020-07-27 06:14:46 +03:00
}
2020-07-14 10:52:47 +03:00
pm_runtime_mark_last_busy ( fsl_lpspi - > dev ) ;
pm_runtime_put_autosuspend ( fsl_lpspi - > dev ) ;
2016-11-22 16:52:17 +03:00
return 0 ;
2021-11-09 13:31:34 +03:00
free_dma :
fsl_lpspi_dma_exit ( controller ) ;
2020-05-23 16:38:59 +03:00
out_pm_get :
2020-07-14 10:52:47 +03:00
pm_runtime_dont_use_autosuspend ( fsl_lpspi - > dev ) ;
pm_runtime_put_sync ( fsl_lpspi - > dev ) ;
pm_runtime_disable ( fsl_lpspi - > dev ) ;
2018-12-07 05:50:34 +03:00
out_controller_put :
spi_controller_put ( controller ) ;
2016-11-22 16:52:17 +03:00
return ret ;
}
static int fsl_lpspi_remove ( struct platform_device * pdev )
{
2018-12-07 05:50:34 +03:00
struct spi_controller * controller = platform_get_drvdata ( pdev ) ;
struct fsl_lpspi_data * fsl_lpspi =
spi_controller_get_devdata ( controller ) ;
2016-11-22 16:52:17 +03:00
2021-11-09 13:31:34 +03:00
fsl_lpspi_dma_exit ( controller ) ;
2019-03-06 09:30:39 +03:00
pm_runtime_disable ( fsl_lpspi - > dev ) ;
return 0 ;
}
2020-08-18 02:58:12 +03:00
static int __maybe_unused fsl_lpspi_suspend ( struct device * dev )
2019-03-06 09:30:39 +03:00
{
int ret ;
pinctrl_pm_select_sleep_state ( dev ) ;
ret = pm_runtime_force_suspend ( dev ) ;
return ret ;
}
2020-08-18 02:58:12 +03:00
static int __maybe_unused fsl_lpspi_resume ( struct device * dev )
2019-03-06 09:30:39 +03:00
{
int ret ;
ret = pm_runtime_force_resume ( dev ) ;
if ( ret ) {
dev_err ( dev , " Error in resume: %d \n " , ret ) ;
return ret ;
}
pinctrl_pm_select_default_state ( dev ) ;
2016-11-22 16:52:17 +03:00
return 0 ;
}
2019-03-06 09:30:39 +03:00
static const struct dev_pm_ops fsl_lpspi_pm_ops = {
SET_RUNTIME_PM_OPS ( fsl_lpspi_runtime_suspend ,
fsl_lpspi_runtime_resume , NULL )
SET_SYSTEM_SLEEP_PM_OPS ( fsl_lpspi_suspend , fsl_lpspi_resume )
} ;
2016-11-22 16:52:17 +03:00
static struct platform_driver fsl_lpspi_driver = {
. driver = {
2017-01-04 12:38:16 +03:00
. name = DRIVER_NAME ,
. of_match_table = fsl_lpspi_dt_ids ,
2019-03-06 09:30:39 +03:00
. pm = & fsl_lpspi_pm_ops ,
2017-01-04 12:38:16 +03:00
} ,
2016-11-22 16:52:17 +03:00
. probe = fsl_lpspi_probe ,
. remove = fsl_lpspi_remove ,
} ;
module_platform_driver ( fsl_lpspi_driver ) ;
2018-12-07 05:50:34 +03:00
MODULE_DESCRIPTION ( " LPSPI Controller driver " ) ;
2016-11-22 16:52:17 +03:00
MODULE_AUTHOR ( " Gao Pan <pandy.gao@nxp.com> " ) ;
2016-12-02 06:50:00 +03:00
MODULE_LICENSE ( " GPL " ) ;