2019-05-28 09:57:06 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2016-02-04 17:13:30 +01:00
/*
* SPI - Engine SPI controller driver
* Copyright 2015 Analog Devices Inc .
* Author : Lars - Peter Clausen < lars @ metafoo . de >
*/
# include <linux/clk.h>
2024-02-07 08:51:25 -06:00
# include <linux/completion.h>
2024-02-02 15:31:32 -06:00
# include <linux/fpga/adi-axi-common.h>
2016-02-04 17:13:30 +01:00
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/of.h>
# include <linux/module.h>
2024-03-04 10:04:25 -06:00
# include <linux/overflow.h>
2016-02-04 17:13:30 +01:00
# include <linux/platform_device.h>
# include <linux/spi/spi.h>
# define SPI_ENGINE_REG_RESET 0x40
# define SPI_ENGINE_REG_INT_ENABLE 0x80
# define SPI_ENGINE_REG_INT_PENDING 0x84
# define SPI_ENGINE_REG_INT_SOURCE 0x88
# define SPI_ENGINE_REG_SYNC_ID 0xc0
# define SPI_ENGINE_REG_CMD_FIFO_ROOM 0xd0
# define SPI_ENGINE_REG_SDO_FIFO_ROOM 0xd4
# define SPI_ENGINE_REG_SDI_FIFO_LEVEL 0xd8
# define SPI_ENGINE_REG_CMD_FIFO 0xe0
# define SPI_ENGINE_REG_SDO_DATA_FIFO 0xe4
# define SPI_ENGINE_REG_SDI_DATA_FIFO 0xe8
# define SPI_ENGINE_REG_SDI_DATA_FIFO_PEEK 0xec
# define SPI_ENGINE_INT_CMD_ALMOST_EMPTY BIT(0)
# define SPI_ENGINE_INT_SDO_ALMOST_EMPTY BIT(1)
# define SPI_ENGINE_INT_SDI_ALMOST_FULL BIT(2)
# define SPI_ENGINE_INT_SYNC BIT(3)
# define SPI_ENGINE_CONFIG_CPHA BIT(0)
# define SPI_ENGINE_CONFIG_CPOL BIT(1)
# define SPI_ENGINE_CONFIG_3WIRE BIT(2)
# define SPI_ENGINE_INST_TRANSFER 0x0
# define SPI_ENGINE_INST_ASSERT 0x1
# define SPI_ENGINE_INST_WRITE 0x2
# define SPI_ENGINE_INST_MISC 0x3
# define SPI_ENGINE_CMD_REG_CLK_DIV 0x0
# define SPI_ENGINE_CMD_REG_CONFIG 0x1
2023-11-17 14:13:05 -06:00
# define SPI_ENGINE_CMD_REG_XFER_BITS 0x2
2016-02-04 17:13:30 +01:00
# define SPI_ENGINE_MISC_SYNC 0x0
# define SPI_ENGINE_MISC_SLEEP 0x1
# define SPI_ENGINE_TRANSFER_WRITE 0x1
# define SPI_ENGINE_TRANSFER_READ 0x2
2024-02-07 08:51:24 -06:00
/* Arbitrary sync ID for use by host->cur_msg */
# define AXI_SPI_ENGINE_CUR_MSG_SYNC_ID 0x1
2016-02-04 17:13:30 +01:00
# define SPI_ENGINE_CMD(inst, arg1, arg2) \
( ( ( inst ) < < 12 ) | ( ( arg1 ) < < 8 ) | ( arg2 ) )
# define SPI_ENGINE_CMD_TRANSFER(flags, n) \
SPI_ENGINE_CMD ( SPI_ENGINE_INST_TRANSFER , ( flags ) , ( n ) )
# define SPI_ENGINE_CMD_ASSERT(delay, cs) \
SPI_ENGINE_CMD ( SPI_ENGINE_INST_ASSERT , ( delay ) , ( cs ) )
# define SPI_ENGINE_CMD_WRITE(reg, val) \
SPI_ENGINE_CMD ( SPI_ENGINE_INST_WRITE , ( reg ) , ( val ) )
# define SPI_ENGINE_CMD_SLEEP(delay) \
SPI_ENGINE_CMD ( SPI_ENGINE_INST_MISC , SPI_ENGINE_MISC_SLEEP , ( delay ) )
# define SPI_ENGINE_CMD_SYNC(id) \
SPI_ENGINE_CMD ( SPI_ENGINE_INST_MISC , SPI_ENGINE_MISC_SYNC , ( id ) )
struct spi_engine_program {
unsigned int length ;
2024-03-04 10:04:24 -06:00
uint16_t instructions [ ] __counted_by ( length ) ;
2016-02-04 17:13:30 +01:00
} ;
2023-11-17 14:13:00 -06:00
/**
* struct spi_engine_message_state - SPI engine per - message state
*/
struct spi_engine_message_state {
2023-12-18 08:53:45 -06:00
/** @cmd_length: Number of elements in cmd_buf array. */
2016-02-04 17:13:30 +01:00
unsigned cmd_length ;
2023-12-18 08:53:45 -06:00
/** @cmd_buf: Array of commands not yet written to CMD FIFO. */
2016-02-04 17:13:30 +01:00
const uint16_t * cmd_buf ;
2023-12-18 08:53:45 -06:00
/** @tx_xfer: Next xfer with tx_buf not yet fully written to TX FIFO. */
2016-02-04 17:13:30 +01:00
struct spi_transfer * tx_xfer ;
2023-12-18 08:53:45 -06:00
/** @tx_length: Size of tx_buf in bytes. */
2016-02-04 17:13:30 +01:00
unsigned int tx_length ;
2023-12-18 08:53:45 -06:00
/** @tx_buf: Bytes not yet written to TX FIFO. */
2016-02-04 17:13:30 +01:00
const uint8_t * tx_buf ;
2023-12-18 08:53:45 -06:00
/** @rx_xfer: Next xfer with rx_buf not yet fully written to RX FIFO. */
2016-02-04 17:13:30 +01:00
struct spi_transfer * rx_xfer ;
2023-12-18 08:53:45 -06:00
/** @rx_length: Size of tx_buf in bytes. */
2016-02-04 17:13:30 +01:00
unsigned int rx_length ;
2023-12-18 08:53:45 -06:00
/** @rx_buf: Bytes not yet written to the RX FIFO. */
2016-02-04 17:13:30 +01:00
uint8_t * rx_buf ;
2023-11-17 14:13:00 -06:00
} ;
struct spi_engine {
struct clk * clk ;
struct clk * ref_clk ;
spinlock_t lock ;
void __iomem * base ;
2024-02-19 16:33:21 -06:00
struct spi_engine_message_state msg_state ;
2024-02-07 08:51:25 -06:00
struct completion msg_complete ;
2016-02-04 17:13:30 +01:00
unsigned int int_enable ;
} ;
static void spi_engine_program_add_cmd ( struct spi_engine_program * p ,
bool dry , uint16_t cmd )
{
p - > length + + ;
2024-03-04 10:04:24 -06:00
if ( ! dry )
p - > instructions [ p - > length - 1 ] = cmd ;
2016-02-04 17:13:30 +01:00
}
static unsigned int spi_engine_get_config ( struct spi_device * spi )
{
unsigned int config = 0 ;
if ( spi - > mode & SPI_CPOL )
config | = SPI_ENGINE_CONFIG_CPOL ;
if ( spi - > mode & SPI_CPHA )
config | = SPI_ENGINE_CONFIG_CPHA ;
if ( spi - > mode & SPI_3WIRE )
config | = SPI_ENGINE_CONFIG_3WIRE ;
return config ;
}
static void spi_engine_gen_xfer ( struct spi_engine_program * p , bool dry ,
struct spi_transfer * xfer )
{
2023-11-17 14:13:05 -06:00
unsigned int len ;
if ( xfer - > bits_per_word < = 8 )
len = xfer - > len ;
else if ( xfer - > bits_per_word < = 16 )
len = xfer - > len / 2 ;
else
len = xfer - > len / 4 ;
2016-02-04 17:13:30 +01:00
while ( len ) {
unsigned int n = min ( len , 256U ) ;
unsigned int flags = 0 ;
if ( xfer - > tx_buf )
flags | = SPI_ENGINE_TRANSFER_WRITE ;
if ( xfer - > rx_buf )
flags | = SPI_ENGINE_TRANSFER_READ ;
spi_engine_program_add_cmd ( p , dry ,
SPI_ENGINE_CMD_TRANSFER ( flags , n - 1 ) ) ;
len - = n ;
}
}
static void spi_engine_gen_sleep ( struct spi_engine_program * p , bool dry ,
2023-12-04 11:33:31 -06:00
int delay_ns , u32 sclk_hz )
2016-02-04 17:13:30 +01:00
{
unsigned int t ;
2019-09-26 13:51:47 +03:00
2023-12-04 11:33:31 -06:00
/* negative delay indicates error, e.g. from spi_delay_to_ns() */
2023-12-04 11:33:30 -06:00
if ( delay_ns < = 0 )
2021-03-08 16:54:53 +02:00
return ;
2016-02-04 17:13:30 +01:00
2023-12-04 11:33:30 -06:00
/* rounding down since executing the instruction adds a couple of ticks delay */
2023-12-04 11:33:31 -06:00
t = DIV_ROUND_DOWN_ULL ( ( u64 ) delay_ns * sclk_hz , NSEC_PER_SEC ) ;
2016-02-04 17:13:30 +01:00
while ( t ) {
unsigned int n = min ( t , 256U ) ;
spi_engine_program_add_cmd ( p , dry , SPI_ENGINE_CMD_SLEEP ( n - 1 ) ) ;
t - = n ;
}
}
static void spi_engine_gen_cs ( struct spi_engine_program * p , bool dry ,
struct spi_device * spi , bool assert )
{
unsigned int mask = 0xff ;
if ( assert )
2023-03-10 23:02:03 +05:30
mask ^ = BIT ( spi_get_chipselect ( spi , 0 ) ) ;
2016-02-04 17:13:30 +01:00
2023-12-04 11:33:34 -06:00
spi_engine_program_add_cmd ( p , dry , SPI_ENGINE_CMD_ASSERT ( 0 , mask ) ) ;
2016-02-04 17:13:30 +01:00
}
2023-12-04 11:33:28 -06:00
/*
* Performs precompile steps on the message .
*
* The SPI core does most of the message / transfer validation and filling in
* fields for us via __spi_validate ( ) . This fixes up anything remaining not
* done there .
*
* NB : This is separate from spi_engine_compile_message ( ) because the latter
* is called twice and would otherwise result in double - evaluation .
*/
static void spi_engine_precompile_message ( struct spi_message * msg )
{
unsigned int clk_div , max_hz = msg - > spi - > controller - > max_speed_hz ;
struct spi_transfer * xfer ;
list_for_each_entry ( xfer , & msg - > transfers , transfer_list ) {
clk_div = DIV_ROUND_UP ( max_hz , xfer - > speed_hz ) ;
xfer - > effective_speed_hz = max_hz / min ( clk_div , 256U ) ;
}
}
2023-12-04 11:33:30 -06:00
static void spi_engine_compile_message ( struct spi_message * msg , bool dry ,
struct spi_engine_program * p )
2016-02-04 17:13:30 +01:00
{
struct spi_device * spi = msg - > spi ;
2023-12-04 11:33:29 -06:00
struct spi_controller * host = spi - > controller ;
2016-02-04 17:13:30 +01:00
struct spi_transfer * xfer ;
int clk_div , new_clk_div ;
2023-11-17 14:13:04 -06:00
bool keep_cs = false ;
2023-11-17 14:13:05 -06:00
u8 bits_per_word = 0 ;
2016-02-04 17:13:30 +01:00
2023-12-04 11:33:33 -06:00
clk_div = 1 ;
2016-02-04 17:13:30 +01:00
spi_engine_program_add_cmd ( p , dry ,
SPI_ENGINE_CMD_WRITE ( SPI_ENGINE_CMD_REG_CONFIG ,
spi_engine_get_config ( spi ) ) ) ;
2023-11-17 14:13:04 -06:00
xfer = list_first_entry ( & msg - > transfers , struct spi_transfer , transfer_list ) ;
spi_engine_gen_cs ( p , dry , spi , ! xfer - > cs_off ) ;
2016-02-04 17:13:30 +01:00
list_for_each_entry ( xfer , & msg - > transfers , transfer_list ) {
2023-12-04 11:33:29 -06:00
new_clk_div = host - > max_speed_hz / xfer - > effective_speed_hz ;
2016-02-04 17:13:30 +01:00
if ( new_clk_div ! = clk_div ) {
clk_div = new_clk_div ;
2023-12-04 11:33:29 -06:00
/* actual divider used is register value + 1 */
2016-02-04 17:13:30 +01:00
spi_engine_program_add_cmd ( p , dry ,
SPI_ENGINE_CMD_WRITE ( SPI_ENGINE_CMD_REG_CLK_DIV ,
2023-12-04 11:33:29 -06:00
clk_div - 1 ) ) ;
2016-02-04 17:13:30 +01:00
}
2023-11-17 14:13:05 -06:00
if ( bits_per_word ! = xfer - > bits_per_word ) {
bits_per_word = xfer - > bits_per_word ;
spi_engine_program_add_cmd ( p , dry ,
SPI_ENGINE_CMD_WRITE ( SPI_ENGINE_CMD_REG_XFER_BITS ,
bits_per_word ) ) ;
}
2016-02-04 17:13:30 +01:00
spi_engine_gen_xfer ( p , dry , xfer ) ;
2023-12-04 11:33:31 -06:00
spi_engine_gen_sleep ( p , dry , spi_delay_to_ns ( & xfer - > delay , xfer ) ,
xfer - > effective_speed_hz ) ;
2016-02-04 17:13:30 +01:00
2023-11-17 14:13:04 -06:00
if ( xfer - > cs_change ) {
if ( list_is_last ( & xfer - > transfer_list , & msg - > transfers ) ) {
keep_cs = true ;
} else {
if ( ! xfer - > cs_off )
spi_engine_gen_cs ( p , dry , spi , false ) ;
2023-12-04 11:33:32 -06:00
spi_engine_gen_sleep ( p , dry , spi_delay_to_ns (
& xfer - > cs_change_delay , xfer ) ,
xfer - > effective_speed_hz ) ;
2023-11-17 14:13:04 -06:00
if ( ! list_next_entry ( xfer , transfer_list ) - > cs_off )
spi_engine_gen_cs ( p , dry , spi , true ) ;
}
} else if ( ! list_is_last ( & xfer - > transfer_list , & msg - > transfers ) & &
xfer - > cs_off ! = list_next_entry ( xfer , transfer_list ) - > cs_off ) {
spi_engine_gen_cs ( p , dry , spi , xfer - > cs_off ) ;
}
2016-02-04 17:13:30 +01:00
}
2023-11-17 14:13:04 -06:00
if ( ! keep_cs )
spi_engine_gen_cs ( p , dry , spi , false ) ;
2023-12-04 11:33:33 -06:00
/*
* Restore clockdiv to default so that future gen_sleep commands don ' t
* have to be aware of the current register state .
*/
if ( clk_div ! = 1 )
spi_engine_program_add_cmd ( p , dry ,
SPI_ENGINE_CMD_WRITE ( SPI_ENGINE_CMD_REG_CLK_DIV , 0 ) ) ;
2016-02-04 17:13:30 +01:00
}
2023-11-17 14:13:03 -06:00
static void spi_engine_xfer_next ( struct spi_message * msg ,
2016-02-04 17:13:30 +01:00
struct spi_transfer * * _xfer )
{
struct spi_transfer * xfer = * _xfer ;
if ( ! xfer ) {
xfer = list_first_entry ( & msg - > transfers ,
struct spi_transfer , transfer_list ) ;
} else if ( list_is_last ( & xfer - > transfer_list , & msg - > transfers ) ) {
xfer = NULL ;
} else {
xfer = list_next_entry ( xfer , transfer_list ) ;
}
* _xfer = xfer ;
}
2023-11-17 14:13:03 -06:00
static void spi_engine_tx_next ( struct spi_message * msg )
2016-02-04 17:13:30 +01:00
{
2023-11-17 14:13:03 -06:00
struct spi_engine_message_state * st = msg - > state ;
2023-11-17 14:13:00 -06:00
struct spi_transfer * xfer = st - > tx_xfer ;
2016-02-04 17:13:30 +01:00
do {
2023-11-17 14:13:03 -06:00
spi_engine_xfer_next ( msg , & xfer ) ;
2016-02-04 17:13:30 +01:00
} while ( xfer & & ! xfer - > tx_buf ) ;
2023-11-17 14:13:00 -06:00
st - > tx_xfer = xfer ;
2016-02-04 17:13:30 +01:00
if ( xfer ) {
2023-11-17 14:13:00 -06:00
st - > tx_length = xfer - > len ;
st - > tx_buf = xfer - > tx_buf ;
2016-02-04 17:13:30 +01:00
} else {
2023-11-17 14:13:00 -06:00
st - > tx_buf = NULL ;
2016-02-04 17:13:30 +01:00
}
}
2023-11-17 14:13:03 -06:00
static void spi_engine_rx_next ( struct spi_message * msg )
2016-02-04 17:13:30 +01:00
{
2023-11-17 14:13:03 -06:00
struct spi_engine_message_state * st = msg - > state ;
2023-11-17 14:13:00 -06:00
struct spi_transfer * xfer = st - > rx_xfer ;
2016-02-04 17:13:30 +01:00
do {
2023-11-17 14:13:03 -06:00
spi_engine_xfer_next ( msg , & xfer ) ;
2016-02-04 17:13:30 +01:00
} while ( xfer & & ! xfer - > rx_buf ) ;
2023-11-17 14:13:00 -06:00
st - > rx_xfer = xfer ;
2016-02-04 17:13:30 +01:00
if ( xfer ) {
2023-11-17 14:13:00 -06:00
st - > rx_length = xfer - > len ;
st - > rx_buf = xfer - > rx_buf ;
2016-02-04 17:13:30 +01:00
} else {
2023-11-17 14:13:00 -06:00
st - > rx_buf = NULL ;
2016-02-04 17:13:30 +01:00
}
}
2023-11-17 14:13:03 -06:00
static bool spi_engine_write_cmd_fifo ( struct spi_engine * spi_engine ,
struct spi_message * msg )
2016-02-04 17:13:30 +01:00
{
void __iomem * addr = spi_engine - > base + SPI_ENGINE_REG_CMD_FIFO ;
2023-11-17 14:13:03 -06:00
struct spi_engine_message_state * st = msg - > state ;
2016-02-04 17:13:30 +01:00
unsigned int n , m , i ;
const uint16_t * buf ;
n = readl_relaxed ( spi_engine - > base + SPI_ENGINE_REG_CMD_FIFO_ROOM ) ;
2023-11-17 14:13:00 -06:00
while ( n & & st - > cmd_length ) {
m = min ( n , st - > cmd_length ) ;
buf = st - > cmd_buf ;
2016-02-04 17:13:30 +01:00
for ( i = 0 ; i < m ; i + + )
writel_relaxed ( buf [ i ] , addr ) ;
2023-11-17 14:13:00 -06:00
st - > cmd_buf + = m ;
st - > cmd_length - = m ;
2016-02-04 17:13:30 +01:00
n - = m ;
}
2023-11-17 14:13:00 -06:00
return st - > cmd_length ! = 0 ;
2016-02-04 17:13:30 +01:00
}
2023-11-17 14:13:03 -06:00
static bool spi_engine_write_tx_fifo ( struct spi_engine * spi_engine ,
struct spi_message * msg )
2016-02-04 17:13:30 +01:00
{
void __iomem * addr = spi_engine - > base + SPI_ENGINE_REG_SDO_DATA_FIFO ;
2023-11-17 14:13:03 -06:00
struct spi_engine_message_state * st = msg - > state ;
2016-02-04 17:13:30 +01:00
unsigned int n , m , i ;
n = readl_relaxed ( spi_engine - > base + SPI_ENGINE_REG_SDO_FIFO_ROOM ) ;
2023-11-17 14:13:00 -06:00
while ( n & & st - > tx_length ) {
2023-11-17 14:13:05 -06:00
if ( st - > tx_xfer - > bits_per_word < = 8 ) {
const u8 * buf = st - > tx_buf ;
m = min ( n , st - > tx_length ) ;
for ( i = 0 ; i < m ; i + + )
writel_relaxed ( buf [ i ] , addr ) ;
st - > tx_buf + = m ;
st - > tx_length - = m ;
} else if ( st - > tx_xfer - > bits_per_word < = 16 ) {
const u16 * buf = ( const u16 * ) st - > tx_buf ;
m = min ( n , st - > tx_length / 2 ) ;
for ( i = 0 ; i < m ; i + + )
writel_relaxed ( buf [ i ] , addr ) ;
st - > tx_buf + = m * 2 ;
st - > tx_length - = m * 2 ;
} else {
const u32 * buf = ( const u32 * ) st - > tx_buf ;
m = min ( n , st - > tx_length / 4 ) ;
for ( i = 0 ; i < m ; i + + )
writel_relaxed ( buf [ i ] , addr ) ;
st - > tx_buf + = m * 4 ;
st - > tx_length - = m * 4 ;
}
2016-02-04 17:13:30 +01:00
n - = m ;
2023-11-17 14:13:00 -06:00
if ( st - > tx_length = = 0 )
2023-11-17 14:13:03 -06:00
spi_engine_tx_next ( msg ) ;
2016-02-04 17:13:30 +01:00
}
2023-11-17 14:13:00 -06:00
return st - > tx_length ! = 0 ;
2016-02-04 17:13:30 +01:00
}
2023-11-17 14:13:03 -06:00
static bool spi_engine_read_rx_fifo ( struct spi_engine * spi_engine ,
struct spi_message * msg )
2016-02-04 17:13:30 +01:00
{
void __iomem * addr = spi_engine - > base + SPI_ENGINE_REG_SDI_DATA_FIFO ;
2023-11-17 14:13:03 -06:00
struct spi_engine_message_state * st = msg - > state ;
2016-02-04 17:13:30 +01:00
unsigned int n , m , i ;
n = readl_relaxed ( spi_engine - > base + SPI_ENGINE_REG_SDI_FIFO_LEVEL ) ;
2023-11-17 14:13:00 -06:00
while ( n & & st - > rx_length ) {
2023-11-17 14:13:05 -06:00
if ( st - > rx_xfer - > bits_per_word < = 8 ) {
u8 * buf = st - > rx_buf ;
m = min ( n , st - > rx_length ) ;
for ( i = 0 ; i < m ; i + + )
buf [ i ] = readl_relaxed ( addr ) ;
st - > rx_buf + = m ;
st - > rx_length - = m ;
} else if ( st - > rx_xfer - > bits_per_word < = 16 ) {
u16 * buf = ( u16 * ) st - > rx_buf ;
m = min ( n , st - > rx_length / 2 ) ;
for ( i = 0 ; i < m ; i + + )
buf [ i ] = readl_relaxed ( addr ) ;
st - > rx_buf + = m * 2 ;
st - > rx_length - = m * 2 ;
} else {
u32 * buf = ( u32 * ) st - > rx_buf ;
m = min ( n , st - > rx_length / 4 ) ;
for ( i = 0 ; i < m ; i + + )
buf [ i ] = readl_relaxed ( addr ) ;
st - > rx_buf + = m * 4 ;
st - > rx_length - = m * 4 ;
}
2016-02-04 17:13:30 +01:00
n - = m ;
2023-11-17 14:13:00 -06:00
if ( st - > rx_length = = 0 )
2023-11-17 14:13:03 -06:00
spi_engine_rx_next ( msg ) ;
2016-02-04 17:13:30 +01:00
}
2023-11-17 14:13:00 -06:00
return st - > rx_length ! = 0 ;
2016-02-04 17:13:30 +01:00
}
static irqreturn_t spi_engine_irq ( int irq , void * devid )
{
2023-07-28 17:32:03 +08:00
struct spi_controller * host = devid ;
2023-11-17 14:13:03 -06:00
struct spi_message * msg = host - > cur_msg ;
2023-07-28 17:32:03 +08:00
struct spi_engine * spi_engine = spi_controller_get_devdata ( host ) ;
2016-02-04 17:13:30 +01:00
unsigned int disable_int = 0 ;
unsigned int pending ;
2023-11-17 14:13:02 -06:00
int completed_id = - 1 ;
2016-02-04 17:13:30 +01:00
pending = readl_relaxed ( spi_engine - > base + SPI_ENGINE_REG_INT_PENDING ) ;
if ( pending & SPI_ENGINE_INT_SYNC ) {
writel_relaxed ( SPI_ENGINE_INT_SYNC ,
spi_engine - > base + SPI_ENGINE_REG_INT_PENDING ) ;
2023-11-17 14:13:02 -06:00
completed_id = readl_relaxed (
2016-02-04 17:13:30 +01:00
spi_engine - > base + SPI_ENGINE_REG_SYNC_ID ) ;
}
spin_lock ( & spi_engine - > lock ) ;
if ( pending & SPI_ENGINE_INT_CMD_ALMOST_EMPTY ) {
2023-11-17 14:13:03 -06:00
if ( ! spi_engine_write_cmd_fifo ( spi_engine , msg ) )
2016-02-04 17:13:30 +01:00
disable_int | = SPI_ENGINE_INT_CMD_ALMOST_EMPTY ;
}
if ( pending & SPI_ENGINE_INT_SDO_ALMOST_EMPTY ) {
2023-11-17 14:13:03 -06:00
if ( ! spi_engine_write_tx_fifo ( spi_engine , msg ) )
2016-02-04 17:13:30 +01:00
disable_int | = SPI_ENGINE_INT_SDO_ALMOST_EMPTY ;
}
if ( pending & ( SPI_ENGINE_INT_SDI_ALMOST_FULL | SPI_ENGINE_INT_SYNC ) ) {
2023-11-17 14:13:03 -06:00
if ( ! spi_engine_read_rx_fifo ( spi_engine , msg ) )
2016-02-04 17:13:30 +01:00
disable_int | = SPI_ENGINE_INT_SDI_ALMOST_FULL ;
}
2023-11-17 14:13:03 -06:00
if ( pending & SPI_ENGINE_INT_SYNC & & msg ) {
2024-02-07 08:51:24 -06:00
if ( completed_id = = AXI_SPI_ENGINE_CUR_MSG_SYNC_ID ) {
2024-02-07 08:51:25 -06:00
msg - > status = 0 ;
msg - > actual_length = msg - > frame_length ;
complete ( & spi_engine - > msg_complete ) ;
2016-02-04 17:13:30 +01:00
disable_int | = SPI_ENGINE_INT_SYNC ;
}
}
if ( disable_int ) {
spi_engine - > int_enable & = ~ disable_int ;
writel_relaxed ( spi_engine - > int_enable ,
spi_engine - > base + SPI_ENGINE_REG_INT_ENABLE ) ;
}
spin_unlock ( & spi_engine - > lock ) ;
return IRQ_HANDLED ;
}
2024-02-19 16:33:21 -06:00
static int spi_engine_optimize_message ( struct spi_message * msg )
2016-02-04 17:13:30 +01:00
{
struct spi_engine_program p_dry , * p ;
2023-11-17 14:13:00 -06:00
2023-12-04 11:33:28 -06:00
spi_engine_precompile_message ( msg ) ;
2016-02-04 17:13:30 +01:00
p_dry . length = 0 ;
2023-12-04 11:33:30 -06:00
spi_engine_compile_message ( msg , true , & p_dry ) ;
2016-02-04 17:13:30 +01:00
2024-03-04 10:04:25 -06:00
p = kzalloc ( struct_size ( p , instructions , p_dry . length + 1 ) , GFP_KERNEL ) ;
2024-02-19 16:33:21 -06:00
if ( ! p )
2016-02-04 17:13:30 +01:00
return - ENOMEM ;
2023-11-17 14:13:00 -06:00
2023-12-04 11:33:30 -06:00
spi_engine_compile_message ( msg , false , p ) ;
2016-02-04 17:13:30 +01:00
2024-02-07 08:51:24 -06:00
spi_engine_program_add_cmd ( p , false , SPI_ENGINE_CMD_SYNC (
AXI_SPI_ENGINE_CUR_MSG_SYNC_ID ) ) ;
2016-02-04 17:13:30 +01:00
2024-02-19 16:33:21 -06:00
msg - > opt_state = p ;
2023-11-17 14:13:01 -06:00
return 0 ;
}
2024-02-19 16:33:21 -06:00
static int spi_engine_unoptimize_message ( struct spi_message * msg )
2023-11-17 14:13:01 -06:00
{
2024-02-19 16:33:21 -06:00
kfree ( msg - > opt_state ) ;
2023-11-17 14:13:01 -06:00
return 0 ;
}
static int spi_engine_transfer_one_message ( struct spi_controller * host ,
struct spi_message * msg )
{
struct spi_engine * spi_engine = spi_controller_get_devdata ( host ) ;
2024-02-19 16:33:21 -06:00
struct spi_engine_message_state * st = & spi_engine - > msg_state ;
struct spi_engine_program * p = msg - > opt_state ;
2023-11-17 14:13:01 -06:00
unsigned int int_enable = 0 ;
unsigned long flags ;
2024-02-19 16:33:21 -06:00
/* reinitialize message state for this transfer */
memset ( st , 0 , sizeof ( * st ) ) ;
st - > cmd_buf = p - > instructions ;
st - > cmd_length = p - > length ;
msg - > state = st ;
2024-02-07 08:51:25 -06:00
reinit_completion ( & spi_engine - > msg_complete ) ;
2023-12-04 11:33:35 -06:00
2023-11-17 14:13:01 -06:00
spin_lock_irqsave ( & spi_engine - > lock , flags ) ;
2023-11-17 14:13:03 -06:00
if ( spi_engine_write_cmd_fifo ( spi_engine , msg ) )
2016-02-04 17:13:30 +01:00
int_enable | = SPI_ENGINE_INT_CMD_ALMOST_EMPTY ;
2023-11-17 14:13:03 -06:00
spi_engine_tx_next ( msg ) ;
if ( spi_engine_write_tx_fifo ( spi_engine , msg ) )
2016-02-04 17:13:30 +01:00
int_enable | = SPI_ENGINE_INT_SDO_ALMOST_EMPTY ;
2023-11-17 14:13:03 -06:00
spi_engine_rx_next ( msg ) ;
2023-11-17 14:13:00 -06:00
if ( st - > rx_length ! = 0 )
2016-02-04 17:13:30 +01:00
int_enable | = SPI_ENGINE_INT_SDI_ALMOST_FULL ;
int_enable | = SPI_ENGINE_INT_SYNC ;
writel_relaxed ( int_enable ,
spi_engine - > base + SPI_ENGINE_REG_INT_ENABLE ) ;
spi_engine - > int_enable = int_enable ;
spin_unlock_irqrestore ( & spi_engine - > lock , flags ) ;
2024-02-07 08:51:25 -06:00
if ( ! wait_for_completion_timeout ( & spi_engine - > msg_complete ,
msecs_to_jiffies ( 5000 ) ) ) {
dev_err ( & host - > dev ,
" Timeout occurred while waiting for transfer to complete. Hardware is probably broken. \n " ) ;
msg - > status = - ETIMEDOUT ;
}
2023-12-04 11:33:35 -06:00
spi_finalize_current_message ( host ) ;
2024-02-07 08:51:25 -06:00
return msg - > status ;
2023-12-04 11:33:35 -06:00
}
2023-11-17 14:12:56 -06:00
static void spi_engine_release_hw ( void * p )
{
struct spi_engine * spi_engine = p ;
writel_relaxed ( 0xff , spi_engine - > base + SPI_ENGINE_REG_INT_PENDING ) ;
writel_relaxed ( 0x00 , spi_engine - > base + SPI_ENGINE_REG_INT_ENABLE ) ;
writel_relaxed ( 0x01 , spi_engine - > base + SPI_ENGINE_REG_RESET ) ;
}
2016-02-04 17:13:30 +01:00
static int spi_engine_probe ( struct platform_device * pdev )
{
struct spi_engine * spi_engine ;
2023-07-28 17:32:03 +08:00
struct spi_controller * host ;
2016-02-04 17:13:30 +01:00
unsigned int version ;
int irq ;
int ret ;
irq = platform_get_irq ( pdev , 0 ) ;
2023-08-02 17:32:38 +08:00
if ( irq < 0 )
return irq ;
2016-02-04 17:13:30 +01:00
2023-11-17 14:12:55 -06:00
host = devm_spi_alloc_host ( & pdev - > dev , sizeof ( * spi_engine ) ) ;
2023-07-28 17:32:03 +08:00
if ( ! host )
2016-02-04 17:13:30 +01:00
return - ENOMEM ;
2023-11-17 14:12:54 -06:00
spi_engine = spi_controller_get_devdata ( host ) ;
2016-02-04 17:13:30 +01:00
spin_lock_init ( & spi_engine - > lock ) ;
2024-02-07 08:51:25 -06:00
init_completion ( & spi_engine - > msg_complete ) ;
2016-02-04 17:13:30 +01:00
2023-08-23 21:39:18 +08:00
spi_engine - > clk = devm_clk_get_enabled ( & pdev - > dev , " s_axi_aclk " ) ;
2023-11-17 14:12:55 -06:00
if ( IS_ERR ( spi_engine - > clk ) )
return PTR_ERR ( spi_engine - > clk ) ;
2016-02-04 17:13:30 +01:00
2023-08-23 21:39:18 +08:00
spi_engine - > ref_clk = devm_clk_get_enabled ( & pdev - > dev , " spi_clk " ) ;
2023-11-17 14:12:55 -06:00
if ( IS_ERR ( spi_engine - > ref_clk ) )
return PTR_ERR ( spi_engine - > ref_clk ) ;
2016-02-04 17:13:30 +01:00
2020-04-09 17:56:21 +02:00
spi_engine - > base = devm_platform_ioremap_resource ( pdev , 0 ) ;
2023-11-17 14:12:55 -06:00
if ( IS_ERR ( spi_engine - > base ) )
return PTR_ERR ( spi_engine - > base ) ;
2020-04-09 17:56:21 +02:00
2024-02-02 15:31:32 -06:00
version = readl ( spi_engine - > base + ADI_AXI_REG_VERSION ) ;
if ( ADI_AXI_PCORE_VER_MAJOR ( version ) ! = 1 ) {
2024-04-12 17:52:48 -05:00
dev_err ( & pdev - > dev , " Unsupported peripheral version %u.%u.%u \n " ,
2024-02-02 15:31:32 -06:00
ADI_AXI_PCORE_VER_MAJOR ( version ) ,
ADI_AXI_PCORE_VER_MINOR ( version ) ,
ADI_AXI_PCORE_VER_PATCH ( version ) ) ;
2023-11-17 14:12:55 -06:00
return - ENODEV ;
2020-04-09 17:56:21 +02:00
}
2016-02-04 17:13:30 +01:00
writel_relaxed ( 0x00 , spi_engine - > base + SPI_ENGINE_REG_RESET ) ;
writel_relaxed ( 0xff , spi_engine - > base + SPI_ENGINE_REG_INT_PENDING ) ;
writel_relaxed ( 0x00 , spi_engine - > base + SPI_ENGINE_REG_INT_ENABLE ) ;
2023-11-17 14:12:56 -06:00
ret = devm_add_action_or_reset ( & pdev - > dev , spi_engine_release_hw ,
spi_engine ) ;
if ( ret )
return ret ;
2023-11-17 14:12:57 -06:00
ret = devm_request_irq ( & pdev - > dev , irq , spi_engine_irq , 0 , pdev - > name ,
host ) ;
2016-02-04 17:13:30 +01:00
if ( ret )
2023-11-17 14:12:55 -06:00
return ret ;
2016-02-04 17:13:30 +01:00
2023-07-28 17:32:03 +08:00
host - > dev . of_node = pdev - > dev . of_node ;
host - > mode_bits = SPI_CPOL | SPI_CPHA | SPI_3WIRE ;
2023-11-17 14:13:05 -06:00
host - > bits_per_word_mask = SPI_BPW_RANGE_MASK ( 1 , 32 ) ;
2023-07-28 17:32:03 +08:00
host - > max_speed_hz = clk_get_rate ( spi_engine - > ref_clk ) / 2 ;
host - > transfer_one_message = spi_engine_transfer_one_message ;
2024-02-19 16:33:21 -06:00
host - > optimize_message = spi_engine_optimize_message ;
host - > unoptimize_message = spi_engine_unoptimize_message ;
2023-07-28 17:32:03 +08:00
host - > num_chipselect = 8 ;
2016-02-04 17:13:30 +01:00
2023-11-17 14:12:59 -06:00
if ( host - > max_speed_hz = = 0 )
return dev_err_probe ( & pdev - > dev , - EINVAL , " spi_clk rate is 0 " ) ;
2023-11-17 14:12:58 -06:00
ret = devm_spi_register_controller ( & pdev - > dev , host ) ;
2016-02-04 17:13:30 +01:00
if ( ret )
2023-11-17 14:12:57 -06:00
return ret ;
2016-02-04 17:13:30 +01:00
2023-07-28 17:32:03 +08:00
platform_set_drvdata ( pdev , host ) ;
2016-02-04 17:13:30 +01:00
return 0 ;
}
static const struct of_device_id spi_engine_match_table [ ] = {
{ . compatible = " adi,axi-spi-engine-1.00.a " } ,
{ } ,
} ;
2016-11-23 13:37:08 -03:00
MODULE_DEVICE_TABLE ( of , spi_engine_match_table ) ;
2016-02-04 17:13:30 +01:00
static struct platform_driver spi_engine_driver = {
. probe = spi_engine_probe ,
. driver = {
. name = " spi-engine " ,
. of_match_table = spi_engine_match_table ,
} ,
} ;
module_platform_driver ( spi_engine_driver ) ;
MODULE_AUTHOR ( " Lars-Peter Clausen <lars@metafoo.de> " ) ;
MODULE_DESCRIPTION ( " Analog Devices SPI engine peripheral driver " ) ;
MODULE_LICENSE ( " GPL " ) ;