2013-06-27 02:07:40 +04:00
/*
* Analog Devices SPI3 controller driver
*
2014-04-04 12:27:17 +04:00
* Copyright ( c ) 2014 Analog Devices Inc .
2013-06-27 02:07:40 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
2014-04-05 07:29:09 +04:00
# include <linux/clk.h>
2013-06-27 02:07:40 +04:00
# include <linux/delay.h>
# include <linux/device.h>
# include <linux/dma-mapping.h>
# include <linux/errno.h>
# include <linux/gpio.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/spi/spi.h>
2014-04-04 12:27:17 +04:00
# include <linux/spi/adi_spi3.h>
2013-06-27 02:07:40 +04:00
# include <linux/types.h>
# include <asm/dma.h>
# include <asm/portmux.h>
2014-04-04 12:27:17 +04:00
enum adi_spi_state {
2013-06-27 02:07:40 +04:00
START_STATE ,
RUNNING_STATE ,
DONE_STATE ,
ERROR_STATE
} ;
2014-04-04 12:27:17 +04:00
struct adi_spi_master ;
2013-06-27 02:07:40 +04:00
2014-04-04 12:27:17 +04:00
struct adi_spi_transfer_ops {
void ( * write ) ( struct adi_spi_master * ) ;
void ( * read ) ( struct adi_spi_master * ) ;
void ( * duplex ) ( struct adi_spi_master * ) ;
2013-06-27 02:07:40 +04:00
} ;
/* runtime info for spi master */
2014-04-04 12:27:17 +04:00
struct adi_spi_master {
2013-06-27 02:07:40 +04:00
/* SPI framework hookup */
struct spi_master * master ;
/* Regs base of SPI controller */
2014-04-04 12:27:17 +04:00
struct adi_spi_regs __iomem * regs ;
2013-06-27 02:07:40 +04:00
/* Pin request list */
u16 * pin_req ;
/* Message Transfer pump */
struct tasklet_struct pump_transfers ;
/* Current message transfer state info */
struct spi_message * cur_msg ;
struct spi_transfer * cur_transfer ;
2014-04-04 12:27:17 +04:00
struct adi_spi_device * cur_chip ;
2013-06-27 02:07:40 +04:00
unsigned transfer_len ;
/* transfer buffer */
void * tx ;
void * tx_end ;
void * rx ;
void * rx_end ;
/* dma info */
unsigned int tx_dma ;
unsigned int rx_dma ;
dma_addr_t tx_dma_addr ;
dma_addr_t rx_dma_addr ;
unsigned long dummy_buffer ; /* used in unidirectional transfer */
unsigned long tx_dma_size ;
unsigned long rx_dma_size ;
int tx_num ;
int rx_num ;
/* store register value for suspend/resume */
u32 control ;
u32 ssel ;
unsigned long sclk ;
2014-04-04 12:27:17 +04:00
enum adi_spi_state state ;
2013-06-27 02:07:40 +04:00
2014-04-04 12:27:17 +04:00
const struct adi_spi_transfer_ops * ops ;
2013-06-27 02:07:40 +04:00
} ;
2014-04-04 12:27:17 +04:00
struct adi_spi_device {
2013-06-27 02:07:40 +04:00
u32 control ;
u32 clock ;
u32 ssel ;
u8 cs ;
u16 cs_chg_udelay ; /* Some devices require > 255usec delay */
u32 cs_gpio ;
u32 tx_dummy_val ; /* tx value for rx only transfer */
bool enable_dma ;
2014-04-04 12:27:17 +04:00
const struct adi_spi_transfer_ops * ops ;
2013-06-27 02:07:40 +04:00
} ;
2014-04-04 12:27:17 +04:00
static void adi_spi_enable ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
u32 ctl ;
ctl = ioread32 ( & drv_data - > regs - > control ) ;
ctl | = SPI_CTL_EN ;
iowrite32 ( ctl , & drv_data - > regs - > control ) ;
2013-06-27 02:07:40 +04:00
}
2014-04-04 12:27:17 +04:00
static void adi_spi_disable ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
u32 ctl ;
ctl = ioread32 ( & drv_data - > regs - > control ) ;
ctl & = ~ SPI_CTL_EN ;
iowrite32 ( ctl , & drv_data - > regs - > control ) ;
2013-06-27 02:07:40 +04:00
}
/* Caculate the SPI_CLOCK register value based on input HZ */
static u32 hz_to_spi_clock ( u32 sclk , u32 speed_hz )
{
u32 spi_clock = sclk / speed_hz ;
if ( spi_clock )
spi_clock - - ;
return spi_clock ;
}
2014-04-04 12:27:17 +04:00
static int adi_spi_flush ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
unsigned long limit = loops_per_jiffy < < 1 ;
/* wait for stop and clear stat */
2014-04-04 12:27:17 +04:00
while ( ! ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_SPIF ) & & - - limit )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
iowrite32 ( 0xFFFFFFFF , & drv_data - > regs - > status ) ;
2013-06-27 02:07:40 +04:00
return limit ;
}
/* Chip select operation functions for cs_change flag */
2014-04-04 12:27:17 +04:00
static void adi_spi_cs_active ( struct adi_spi_master * drv_data , struct adi_spi_device * chip )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
if ( likely ( chip - > cs < MAX_CTRL_CS ) ) {
u32 reg ;
reg = ioread32 ( & drv_data - > regs - > ssel ) ;
reg & = ~ chip - > ssel ;
iowrite32 ( reg , & drv_data - > regs - > ssel ) ;
} else {
2013-06-27 02:07:40 +04:00
gpio_set_value ( chip - > cs_gpio , 0 ) ;
2014-04-04 12:27:17 +04:00
}
2013-06-27 02:07:40 +04:00
}
2014-04-04 12:27:17 +04:00
static void adi_spi_cs_deactive ( struct adi_spi_master * drv_data ,
struct adi_spi_device * chip )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
if ( likely ( chip - > cs < MAX_CTRL_CS ) ) {
u32 reg ;
reg = ioread32 ( & drv_data - > regs - > ssel ) ;
reg | = chip - > ssel ;
iowrite32 ( reg , & drv_data - > regs - > ssel ) ;
} else {
2013-06-27 02:07:40 +04:00
gpio_set_value ( chip - > cs_gpio , 1 ) ;
2014-04-04 12:27:17 +04:00
}
2013-06-27 02:07:40 +04:00
/* Move delay here for consistency */
if ( chip - > cs_chg_udelay )
udelay ( chip - > cs_chg_udelay ) ;
}
/* enable or disable the pin muxed by GPIO and SPI CS to work as SPI CS */
2014-04-04 12:27:17 +04:00
static inline void adi_spi_cs_enable ( struct adi_spi_master * drv_data ,
struct adi_spi_device * chip )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
if ( chip - > cs < MAX_CTRL_CS ) {
u32 reg ;
reg = ioread32 ( & drv_data - > regs - > ssel ) ;
reg | = chip - > ssel > > 8 ;
iowrite32 ( reg , & drv_data - > regs - > ssel ) ;
}
2013-06-27 02:07:40 +04:00
}
2014-04-04 12:27:17 +04:00
static inline void adi_spi_cs_disable ( struct adi_spi_master * drv_data ,
struct adi_spi_device * chip )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
if ( chip - > cs < MAX_CTRL_CS ) {
u32 reg ;
reg = ioread32 ( & drv_data - > regs - > ssel ) ;
reg & = ~ ( chip - > ssel > > 8 ) ;
iowrite32 ( reg , & drv_data - > regs - > ssel ) ;
}
2013-06-27 02:07:40 +04:00
}
/* stop controller and re-config current chip*/
2014-04-04 12:27:17 +04:00
static void adi_spi_restore_state ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
struct adi_spi_device * chip = drv_data - > cur_chip ;
2013-06-27 02:07:40 +04:00
/* Clear status and disable clock */
2014-04-04 12:27:17 +04:00
iowrite32 ( 0xFFFFFFFF , & drv_data - > regs - > status ) ;
iowrite32 ( 0x0 , & drv_data - > regs - > rx_control ) ;
iowrite32 ( 0x0 , & drv_data - > regs - > tx_control ) ;
adi_spi_disable ( drv_data ) ;
2013-06-27 02:07:40 +04:00
/* Load the registers */
2014-04-04 12:27:17 +04:00
iowrite32 ( chip - > control , & drv_data - > regs - > control ) ;
iowrite32 ( chip - > clock , & drv_data - > regs - > clock ) ;
2013-06-27 02:07:40 +04:00
2014-04-04 12:27:17 +04:00
adi_spi_enable ( drv_data ) ;
2013-06-27 02:07:40 +04:00
drv_data - > tx_num = drv_data - > rx_num = 0 ;
/* we always choose tx transfer initiate */
2014-04-04 12:27:17 +04:00
iowrite32 ( SPI_RXCTL_REN , & drv_data - > regs - > rx_control ) ;
iowrite32 ( SPI_TXCTL_TEN | SPI_TXCTL_TTI , & drv_data - > regs - > tx_control ) ;
adi_spi_cs_active ( drv_data , chip ) ;
2013-06-27 02:07:40 +04:00
}
/* discard invalid rx data and empty rfifo */
2014-04-04 12:27:17 +04:00
static inline void dummy_read ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
while ( ! ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE ) )
ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
}
2014-04-04 12:27:17 +04:00
static void adi_spi_u8_write ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
dummy_read ( drv_data ) ;
while ( drv_data - > tx < drv_data - > tx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( * ( u8 * ) ( drv_data - > tx + + ) , & drv_data - > regs - > tfifo ) ;
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
}
}
2014-04-04 12:27:17 +04:00
static void adi_spi_u8_read ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
u32 tx_val = drv_data - > cur_chip - > tx_dummy_val ;
dummy_read ( drv_data ) ;
while ( drv_data - > rx < drv_data - > rx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( tx_val , & drv_data - > regs - > tfifo ) ;
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
* ( u8 * ) ( drv_data - > rx + + ) = ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
}
}
2014-04-04 12:27:17 +04:00
static void adi_spi_u8_duplex ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
dummy_read ( drv_data ) ;
while ( drv_data - > rx < drv_data - > rx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( * ( u8 * ) ( drv_data - > tx + + ) , & drv_data - > regs - > tfifo ) ;
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
* ( u8 * ) ( drv_data - > rx + + ) = ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
}
}
2014-04-04 12:27:17 +04:00
static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u8 = {
. write = adi_spi_u8_write ,
. read = adi_spi_u8_read ,
. duplex = adi_spi_u8_duplex ,
2013-06-27 02:07:40 +04:00
} ;
2014-04-04 12:27:17 +04:00
static void adi_spi_u16_write ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
dummy_read ( drv_data ) ;
while ( drv_data - > tx < drv_data - > tx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( * ( u16 * ) drv_data - > tx , & drv_data - > regs - > tfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > tx + = 2 ;
2014-04-04 12:27:17 +04:00
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
}
}
2014-04-04 12:27:17 +04:00
static void adi_spi_u16_read ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
u32 tx_val = drv_data - > cur_chip - > tx_dummy_val ;
dummy_read ( drv_data ) ;
while ( drv_data - > rx < drv_data - > rx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( tx_val , & drv_data - > regs - > tfifo ) ;
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
* ( u16 * ) drv_data - > rx = ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > rx + = 2 ;
}
}
2014-04-04 12:27:17 +04:00
static void adi_spi_u16_duplex ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
dummy_read ( drv_data ) ;
while ( drv_data - > rx < drv_data - > rx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( * ( u16 * ) drv_data - > tx , & drv_data - > regs - > tfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > tx + = 2 ;
2014-04-04 12:27:17 +04:00
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
* ( u16 * ) drv_data - > rx = ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > rx + = 2 ;
}
}
2014-04-04 12:27:17 +04:00
static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u16 = {
. write = adi_spi_u16_write ,
. read = adi_spi_u16_read ,
. duplex = adi_spi_u16_duplex ,
2013-06-27 02:07:40 +04:00
} ;
2014-04-04 12:27:17 +04:00
static void adi_spi_u32_write ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
dummy_read ( drv_data ) ;
while ( drv_data - > tx < drv_data - > tx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( * ( u32 * ) drv_data - > tx , & drv_data - > regs - > tfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > tx + = 4 ;
2014-04-04 12:27:17 +04:00
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
}
}
2014-04-04 12:27:17 +04:00
static void adi_spi_u32_read ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
u32 tx_val = drv_data - > cur_chip - > tx_dummy_val ;
dummy_read ( drv_data ) ;
while ( drv_data - > rx < drv_data - > rx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( tx_val , & drv_data - > regs - > tfifo ) ;
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
* ( u32 * ) drv_data - > rx = ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > rx + = 4 ;
}
}
2014-04-04 12:27:17 +04:00
static void adi_spi_u32_duplex ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
dummy_read ( drv_data ) ;
while ( drv_data - > rx < drv_data - > rx_end ) {
2014-04-04 12:27:17 +04:00
iowrite32 ( * ( u32 * ) drv_data - > tx , & drv_data - > regs - > tfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > tx + = 4 ;
2014-04-04 12:27:17 +04:00
while ( ioread32 ( & drv_data - > regs - > status ) & SPI_STAT_RFE )
2013-06-27 02:07:40 +04:00
cpu_relax ( ) ;
2014-04-04 12:27:17 +04:00
* ( u32 * ) drv_data - > rx = ioread32 ( & drv_data - > regs - > rfifo ) ;
2013-06-27 02:07:40 +04:00
drv_data - > rx + = 4 ;
}
}
2014-04-04 12:27:17 +04:00
static const struct adi_spi_transfer_ops adi_spi_transfer_ops_u32 = {
. write = adi_spi_u32_write ,
. read = adi_spi_u32_read ,
. duplex = adi_spi_u32_duplex ,
2013-06-27 02:07:40 +04:00
} ;
/* test if there is more transfer to be done */
2014-04-04 12:27:17 +04:00
static void adi_spi_next_transfer ( struct adi_spi_master * drv )
2013-06-27 02:07:40 +04:00
{
struct spi_message * msg = drv - > cur_msg ;
struct spi_transfer * t = drv - > cur_transfer ;
/* Move to next transfer */
if ( t - > transfer_list . next ! = & msg - > transfers ) {
drv - > cur_transfer = list_entry ( t - > transfer_list . next ,
struct spi_transfer , transfer_list ) ;
drv - > state = RUNNING_STATE ;
} else {
drv - > state = DONE_STATE ;
drv - > cur_transfer = NULL ;
}
}
2014-04-04 12:27:17 +04:00
static void adi_spi_giveback ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
struct adi_spi_device * chip = drv_data - > cur_chip ;
2013-06-27 02:07:40 +04:00
2014-04-04 12:27:17 +04:00
adi_spi_cs_deactive ( drv_data , chip ) ;
2013-06-27 02:07:40 +04:00
spi_finalize_current_message ( drv_data - > master ) ;
}
2014-04-04 12:27:17 +04:00
static int adi_spi_setup_transfer ( struct adi_spi_master * drv )
2013-06-27 02:07:40 +04:00
{
struct spi_transfer * t = drv - > cur_transfer ;
u32 cr , cr_width ;
if ( t - > tx_buf ) {
drv - > tx = ( void * ) t - > tx_buf ;
drv - > tx_end = drv - > tx + t - > len ;
} else {
drv - > tx = NULL ;
}
if ( t - > rx_buf ) {
drv - > rx = t - > rx_buf ;
drv - > rx_end = drv - > rx + t - > len ;
} else {
drv - > rx = NULL ;
}
drv - > transfer_len = t - > len ;
/* bits per word setup */
switch ( t - > bits_per_word ) {
case 8 :
cr_width = SPI_CTL_SIZE08 ;
2014-04-04 12:27:17 +04:00
drv - > ops = & adi_spi_transfer_ops_u8 ;
2013-06-27 02:07:40 +04:00
break ;
case 16 :
cr_width = SPI_CTL_SIZE16 ;
2014-04-04 12:27:17 +04:00
drv - > ops = & adi_spi_transfer_ops_u16 ;
2013-06-27 02:07:40 +04:00
break ;
case 32 :
cr_width = SPI_CTL_SIZE32 ;
2014-04-04 12:27:17 +04:00
drv - > ops = & adi_spi_transfer_ops_u32 ;
2013-06-27 02:07:40 +04:00
break ;
default :
return - EINVAL ;
}
2014-04-04 12:27:17 +04:00
cr = ioread32 ( & drv - > regs - > control ) & ~ SPI_CTL_SIZE ;
2013-06-27 02:07:40 +04:00
cr | = cr_width ;
2014-04-04 12:27:17 +04:00
iowrite32 ( cr , & drv - > regs - > control ) ;
2013-06-27 02:07:40 +04:00
/* speed setup */
2014-04-04 12:27:17 +04:00
iowrite32 ( hz_to_spi_clock ( drv - > sclk , t - > speed_hz ) , & drv - > regs - > clock ) ;
2013-06-27 02:07:40 +04:00
return 0 ;
}
2014-04-04 12:27:17 +04:00
static int adi_spi_dma_xfer ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
struct spi_transfer * t = drv_data - > cur_transfer ;
struct spi_message * msg = drv_data - > cur_msg ;
2014-04-04 12:27:17 +04:00
struct adi_spi_device * chip = drv_data - > cur_chip ;
2013-06-27 02:07:40 +04:00
u32 dma_config ;
unsigned long word_count , word_size ;
void * tx_buf , * rx_buf ;
switch ( t - > bits_per_word ) {
case 8 :
dma_config = WDSIZE_8 | PSIZE_8 ;
word_count = drv_data - > transfer_len ;
word_size = 1 ;
break ;
case 16 :
dma_config = WDSIZE_16 | PSIZE_16 ;
word_count = drv_data - > transfer_len / 2 ;
word_size = 2 ;
break ;
default :
dma_config = WDSIZE_32 | PSIZE_32 ;
word_count = drv_data - > transfer_len / 4 ;
word_size = 4 ;
break ;
}
if ( ! drv_data - > rx ) {
tx_buf = drv_data - > tx ;
rx_buf = & drv_data - > dummy_buffer ;
drv_data - > tx_dma_size = drv_data - > transfer_len ;
drv_data - > rx_dma_size = sizeof ( drv_data - > dummy_buffer ) ;
set_dma_x_modify ( drv_data - > tx_dma , word_size ) ;
set_dma_x_modify ( drv_data - > rx_dma , 0 ) ;
} else if ( ! drv_data - > tx ) {
drv_data - > dummy_buffer = chip - > tx_dummy_val ;
tx_buf = & drv_data - > dummy_buffer ;
rx_buf = drv_data - > rx ;
drv_data - > tx_dma_size = sizeof ( drv_data - > dummy_buffer ) ;
drv_data - > rx_dma_size = drv_data - > transfer_len ;
set_dma_x_modify ( drv_data - > tx_dma , 0 ) ;
set_dma_x_modify ( drv_data - > rx_dma , word_size ) ;
} else {
tx_buf = drv_data - > tx ;
rx_buf = drv_data - > rx ;
drv_data - > tx_dma_size = drv_data - > rx_dma_size
= drv_data - > transfer_len ;
set_dma_x_modify ( drv_data - > tx_dma , word_size ) ;
set_dma_x_modify ( drv_data - > rx_dma , word_size ) ;
}
drv_data - > tx_dma_addr = dma_map_single ( & msg - > spi - > dev ,
( void * ) tx_buf ,
drv_data - > tx_dma_size ,
DMA_TO_DEVICE ) ;
if ( dma_mapping_error ( & msg - > spi - > dev ,
drv_data - > tx_dma_addr ) )
return - ENOMEM ;
drv_data - > rx_dma_addr = dma_map_single ( & msg - > spi - > dev ,
( void * ) rx_buf ,
drv_data - > rx_dma_size ,
DMA_FROM_DEVICE ) ;
if ( dma_mapping_error ( & msg - > spi - > dev ,
drv_data - > rx_dma_addr ) ) {
dma_unmap_single ( & msg - > spi - > dev ,
drv_data - > tx_dma_addr ,
drv_data - > tx_dma_size ,
DMA_TO_DEVICE ) ;
return - ENOMEM ;
}
dummy_read ( drv_data ) ;
set_dma_x_count ( drv_data - > tx_dma , word_count ) ;
set_dma_x_count ( drv_data - > rx_dma , word_count ) ;
set_dma_start_addr ( drv_data - > tx_dma , drv_data - > tx_dma_addr ) ;
set_dma_start_addr ( drv_data - > rx_dma , drv_data - > rx_dma_addr ) ;
dma_config | = DMAFLOW_STOP | RESTART | DI_EN ;
set_dma_config ( drv_data - > tx_dma , dma_config ) ;
set_dma_config ( drv_data - > rx_dma , dma_config | WNR ) ;
enable_dma ( drv_data - > tx_dma ) ;
enable_dma ( drv_data - > rx_dma ) ;
2014-04-04 12:27:17 +04:00
iowrite32 ( SPI_RXCTL_REN | SPI_RXCTL_RDR_NE ,
& drv_data - > regs - > rx_control ) ;
iowrite32 ( SPI_TXCTL_TEN | SPI_TXCTL_TTI | SPI_TXCTL_TDR_NF ,
& drv_data - > regs - > tx_control ) ;
2013-06-27 02:07:40 +04:00
return 0 ;
}
2014-04-04 12:27:17 +04:00
static int adi_spi_pio_xfer ( struct adi_spi_master * drv_data )
2013-06-27 02:07:40 +04:00
{
struct spi_message * msg = drv_data - > cur_msg ;
if ( ! drv_data - > rx ) {
/* write only half duplex */
drv_data - > ops - > write ( drv_data ) ;
if ( drv_data - > tx ! = drv_data - > tx_end )
return - EIO ;
} else if ( ! drv_data - > tx ) {
/* read only half duplex */
drv_data - > ops - > read ( drv_data ) ;
if ( drv_data - > rx ! = drv_data - > rx_end )
return - EIO ;
} else {
/* full duplex mode */
drv_data - > ops - > duplex ( drv_data ) ;
if ( drv_data - > tx ! = drv_data - > tx_end )
return - EIO ;
}
2014-04-04 12:27:17 +04:00
if ( ! adi_spi_flush ( drv_data ) )
2013-06-27 02:07:40 +04:00
return - EIO ;
msg - > actual_length + = drv_data - > transfer_len ;
tasklet_schedule ( & drv_data - > pump_transfers ) ;
return 0 ;
}
2014-04-04 12:27:17 +04:00
static void adi_spi_pump_transfers ( unsigned long data )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = ( struct adi_spi_master * ) data ;
2013-06-27 02:07:40 +04:00
struct spi_message * msg = NULL ;
struct spi_transfer * t = NULL ;
2014-04-04 12:27:17 +04:00
struct adi_spi_device * chip = NULL ;
2013-06-27 02:07:40 +04:00
int ret ;
/* Get current state information */
msg = drv_data - > cur_msg ;
t = drv_data - > cur_transfer ;
chip = drv_data - > cur_chip ;
/* Handle for abort */
if ( drv_data - > state = = ERROR_STATE ) {
msg - > status = - EIO ;
2014-04-04 12:27:17 +04:00
adi_spi_giveback ( drv_data ) ;
2013-06-27 02:07:40 +04:00
return ;
}
if ( drv_data - > state = = RUNNING_STATE ) {
if ( t - > delay_usecs )
udelay ( t - > delay_usecs ) ;
if ( t - > cs_change )
2014-04-04 12:27:17 +04:00
adi_spi_cs_deactive ( drv_data , chip ) ;
adi_spi_next_transfer ( drv_data ) ;
2013-06-27 02:07:40 +04:00
t = drv_data - > cur_transfer ;
}
/* Handle end of message */
if ( drv_data - > state = = DONE_STATE ) {
msg - > status = 0 ;
2014-04-04 12:27:17 +04:00
adi_spi_giveback ( drv_data ) ;
2013-06-27 02:07:40 +04:00
return ;
}
if ( ( t - > len = = 0 ) | | ( t - > tx_buf = = NULL & & t - > rx_buf = = NULL ) ) {
/* Schedule next transfer tasklet */
tasklet_schedule ( & drv_data - > pump_transfers ) ;
return ;
}
2014-04-04 12:27:17 +04:00
ret = adi_spi_setup_transfer ( drv_data ) ;
2013-06-27 02:07:40 +04:00
if ( ret ) {
msg - > status = ret ;
2014-04-04 12:27:17 +04:00
adi_spi_giveback ( drv_data ) ;
2013-06-27 02:07:40 +04:00
}
2014-04-04 12:27:17 +04:00
iowrite32 ( 0xFFFFFFFF , & drv_data - > regs - > status ) ;
adi_spi_cs_active ( drv_data , chip ) ;
2013-06-27 02:07:40 +04:00
drv_data - > state = RUNNING_STATE ;
if ( chip - > enable_dma )
2014-04-04 12:27:17 +04:00
ret = adi_spi_dma_xfer ( drv_data ) ;
2013-06-27 02:07:40 +04:00
else
2014-04-04 12:27:17 +04:00
ret = adi_spi_pio_xfer ( drv_data ) ;
2013-06-27 02:07:40 +04:00
if ( ret ) {
msg - > status = ret ;
2014-04-04 12:27:17 +04:00
adi_spi_giveback ( drv_data ) ;
2013-06-27 02:07:40 +04:00
}
}
2014-04-04 12:27:17 +04:00
static int adi_spi_transfer_one_message ( struct spi_master * master ,
2013-06-27 02:07:40 +04:00
struct spi_message * m )
{
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = spi_master_get_devdata ( master ) ;
2013-06-27 02:07:40 +04:00
drv_data - > cur_msg = m ;
drv_data - > cur_chip = spi_get_ctldata ( drv_data - > cur_msg - > spi ) ;
2014-04-04 12:27:17 +04:00
adi_spi_restore_state ( drv_data ) ;
2013-06-27 02:07:40 +04:00
drv_data - > state = START_STATE ;
drv_data - > cur_transfer = list_entry ( drv_data - > cur_msg - > transfers . next ,
struct spi_transfer , transfer_list ) ;
tasklet_schedule ( & drv_data - > pump_transfers ) ;
return 0 ;
}
# define MAX_SPI_SSEL 7
static const u16 ssel [ ] [ MAX_SPI_SSEL ] = {
{ P_SPI0_SSEL1 , P_SPI0_SSEL2 , P_SPI0_SSEL3 ,
P_SPI0_SSEL4 , P_SPI0_SSEL5 ,
P_SPI0_SSEL6 , P_SPI0_SSEL7 } ,
{ P_SPI1_SSEL1 , P_SPI1_SSEL2 , P_SPI1_SSEL3 ,
P_SPI1_SSEL4 , P_SPI1_SSEL5 ,
P_SPI1_SSEL6 , P_SPI1_SSEL7 } ,
{ P_SPI2_SSEL1 , P_SPI2_SSEL2 , P_SPI2_SSEL3 ,
P_SPI2_SSEL4 , P_SPI2_SSEL5 ,
P_SPI2_SSEL6 , P_SPI2_SSEL7 } ,
} ;
2014-04-04 12:27:17 +04:00
static int adi_spi_setup ( struct spi_device * spi )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = spi_master_get_devdata ( spi - > master ) ;
struct adi_spi_device * chip = spi_get_ctldata ( spi ) ;
u32 ctl_reg = SPI_CTL_ODM | SPI_CTL_PSSE ;
2013-06-27 02:07:40 +04:00
int ret = - EINVAL ;
if ( ! chip ) {
2014-04-04 12:27:17 +04:00
struct adi_spi3_chip * chip_info = spi - > controller_data ;
2013-06-27 02:07:40 +04:00
chip = kzalloc ( sizeof ( * chip ) , GFP_KERNEL ) ;
2014-06-13 08:47:41 +04:00
if ( ! chip )
2013-06-27 02:07:40 +04:00
return - ENOMEM ;
2014-06-13 08:47:41 +04:00
2013-06-27 02:07:40 +04:00
if ( chip_info ) {
2014-04-04 12:27:17 +04:00
if ( chip_info - > control & ~ ctl_reg ) {
2013-06-27 02:07:40 +04:00
dev_err ( & spi - > dev ,
" do not set bits that the SPI framework manages \n " ) ;
goto error ;
}
chip - > control = chip_info - > control ;
chip - > cs_chg_udelay = chip_info - > cs_chg_udelay ;
chip - > tx_dummy_val = chip_info - > tx_dummy_val ;
chip - > enable_dma = chip_info - > enable_dma ;
}
chip - > cs = spi - > chip_select ;
2014-04-04 12:27:17 +04:00
2013-06-27 02:07:40 +04:00
if ( chip - > cs < MAX_CTRL_CS ) {
chip - > ssel = ( 1 < < chip - > cs ) < < 8 ;
ret = peripheral_request ( ssel [ spi - > master - > bus_num ]
[ chip - > cs - 1 ] , dev_name ( & spi - > dev ) ) ;
if ( ret ) {
dev_err ( & spi - > dev , " peripheral_request() error \n " ) ;
goto error ;
}
} else {
chip - > cs_gpio = chip - > cs - MAX_CTRL_CS ;
ret = gpio_request_one ( chip - > cs_gpio , GPIOF_OUT_INIT_HIGH ,
dev_name ( & spi - > dev ) ) ;
if ( ret ) {
dev_err ( & spi - > dev , " gpio_request_one() error \n " ) ;
goto error ;
}
}
spi_set_ctldata ( spi , chip ) ;
}
/* force a default base state */
2014-04-04 12:27:17 +04:00
chip - > control & = ctl_reg ;
2013-06-27 02:07:40 +04:00
if ( spi - > mode & SPI_CPOL )
chip - > control | = SPI_CTL_CPOL ;
if ( spi - > mode & SPI_CPHA )
chip - > control | = SPI_CTL_CPHA ;
if ( spi - > mode & SPI_LSB_FIRST )
chip - > control | = SPI_CTL_LSBF ;
chip - > control | = SPI_CTL_MSTR ;
/* we choose software to controll cs */
chip - > control & = ~ SPI_CTL_ASSEL ;
chip - > clock = hz_to_spi_clock ( drv_data - > sclk , spi - > max_speed_hz ) ;
2014-04-04 12:27:17 +04:00
adi_spi_cs_enable ( drv_data , chip ) ;
adi_spi_cs_deactive ( drv_data , chip ) ;
2013-06-27 02:07:40 +04:00
return 0 ;
error :
if ( chip ) {
kfree ( chip ) ;
spi_set_ctldata ( spi , NULL ) ;
}
return ret ;
}
2014-04-04 12:27:17 +04:00
static void adi_spi_cleanup ( struct spi_device * spi )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
struct adi_spi_device * chip = spi_get_ctldata ( spi ) ;
struct adi_spi_master * drv_data = spi_master_get_devdata ( spi - > master ) ;
2013-06-27 02:07:40 +04:00
if ( ! chip )
return ;
if ( chip - > cs < MAX_CTRL_CS ) {
peripheral_free ( ssel [ spi - > master - > bus_num ]
[ chip - > cs - 1 ] ) ;
2014-04-04 12:27:17 +04:00
adi_spi_cs_disable ( drv_data , chip ) ;
2013-06-27 02:07:40 +04:00
} else {
gpio_free ( chip - > cs_gpio ) ;
}
kfree ( chip ) ;
spi_set_ctldata ( spi , NULL ) ;
}
2014-04-04 12:27:17 +04:00
static irqreturn_t adi_spi_tx_dma_isr ( int irq , void * dev_id )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = dev_id ;
2013-06-27 02:07:40 +04:00
u32 dma_stat = get_dma_curr_irqstat ( drv_data - > tx_dma ) ;
2014-04-04 12:27:17 +04:00
u32 tx_ctl ;
2013-06-27 02:07:40 +04:00
clear_dma_irqstat ( drv_data - > tx_dma ) ;
if ( dma_stat & DMA_DONE ) {
drv_data - > tx_num + + ;
} else {
dev_err ( & drv_data - > master - > dev ,
" spi tx dma error: %d \n " , dma_stat ) ;
if ( drv_data - > tx )
drv_data - > state = ERROR_STATE ;
}
2014-04-04 12:27:17 +04:00
tx_ctl = ioread32 ( & drv_data - > regs - > tx_control ) ;
tx_ctl & = ~ SPI_TXCTL_TDR_NF ;
iowrite32 ( tx_ctl , & drv_data - > regs - > tx_control ) ;
2013-06-27 02:07:40 +04:00
return IRQ_HANDLED ;
}
2014-04-04 12:27:17 +04:00
static irqreturn_t adi_spi_rx_dma_isr ( int irq , void * dev_id )
2013-06-27 02:07:40 +04:00
{
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = dev_id ;
2013-06-27 02:07:40 +04:00
struct spi_message * msg = drv_data - > cur_msg ;
u32 dma_stat = get_dma_curr_irqstat ( drv_data - > rx_dma ) ;
clear_dma_irqstat ( drv_data - > rx_dma ) ;
if ( dma_stat & DMA_DONE ) {
drv_data - > rx_num + + ;
/* we may fail on tx dma */
if ( drv_data - > state ! = ERROR_STATE )
msg - > actual_length + = drv_data - > transfer_len ;
} else {
drv_data - > state = ERROR_STATE ;
dev_err ( & drv_data - > master - > dev ,
" spi rx dma error: %d \n " , dma_stat ) ;
}
2014-04-04 12:27:17 +04:00
iowrite32 ( 0 , & drv_data - > regs - > tx_control ) ;
iowrite32 ( 0 , & drv_data - > regs - > rx_control ) ;
2013-06-27 02:07:40 +04:00
if ( drv_data - > rx_num ! = drv_data - > tx_num )
dev_dbg ( & drv_data - > master - > dev ,
" dma interrupt missing: tx=%d,rx=%d \n " ,
drv_data - > tx_num , drv_data - > rx_num ) ;
tasklet_schedule ( & drv_data - > pump_transfers ) ;
return IRQ_HANDLED ;
}
2014-04-04 12:27:17 +04:00
static int adi_spi_probe ( struct platform_device * pdev )
2013-06-27 02:07:40 +04:00
{
struct device * dev = & pdev - > dev ;
2014-04-04 12:27:17 +04:00
struct adi_spi3_master * info = dev_get_platdata ( dev ) ;
2013-06-27 02:07:40 +04:00
struct spi_master * master ;
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data ;
2013-06-27 02:07:40 +04:00
struct resource * mem , * res ;
unsigned int tx_dma , rx_dma ;
2014-04-05 07:29:09 +04:00
struct clk * sclk ;
2013-06-27 02:07:40 +04:00
int ret ;
if ( ! info ) {
dev_err ( dev , " platform data missing! \n " ) ;
return - ENODEV ;
}
2014-04-05 07:29:09 +04:00
sclk = devm_clk_get ( dev , " spi " ) ;
if ( IS_ERR ( sclk ) ) {
dev_err ( dev , " can not get spi clock \n " ) ;
return PTR_ERR ( sclk ) ;
2013-06-27 02:07:40 +04:00
}
res = platform_get_resource ( pdev , IORESOURCE_DMA , 0 ) ;
if ( ! res ) {
dev_err ( dev , " can not get tx dma resource \n " ) ;
return - ENXIO ;
}
tx_dma = res - > start ;
res = platform_get_resource ( pdev , IORESOURCE_DMA , 1 ) ;
if ( ! res ) {
dev_err ( dev , " can not get rx dma resource \n " ) ;
return - ENXIO ;
}
rx_dma = res - > start ;
/* allocate master with space for drv_data */
master = spi_alloc_master ( dev , sizeof ( * drv_data ) ) ;
if ( ! master ) {
dev_err ( dev , " can not alloc spi_master \n " ) ;
return - ENOMEM ;
}
platform_set_drvdata ( pdev , master ) ;
/* the mode bits supported by this driver */
master - > mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST ;
master - > bus_num = pdev - > id ;
master - > num_chipselect = info - > num_chipselect ;
2014-04-04 12:27:17 +04:00
master - > cleanup = adi_spi_cleanup ;
master - > setup = adi_spi_setup ;
master - > transfer_one_message = adi_spi_transfer_one_message ;
2014-02-05 17:59:18 +04:00
master - > bits_per_word_mask = SPI_BPW_MASK ( 32 ) | SPI_BPW_MASK ( 16 ) |
SPI_BPW_MASK ( 8 ) ;
2013-06-27 02:07:40 +04:00
drv_data = spi_master_get_devdata ( master ) ;
drv_data - > master = master ;
drv_data - > tx_dma = tx_dma ;
drv_data - > rx_dma = rx_dma ;
drv_data - > pin_req = info - > pin_req ;
2014-04-05 07:29:09 +04:00
drv_data - > sclk = clk_get_rate ( sclk ) ;
2013-06-27 02:07:40 +04:00
spi/spi-{bcm63xx.c,bfin-v3.c}: simplify use of devm_ioremap_resource
Remove unneeded error handling on the result of a call to
platform_get_resource when the value is passed to devm_ioremap_resource.
Move the call to platform_get_resource adjacent to the call to
devm_ioremap_resource to make the connection between them more clear.
A simplified version of the semantic patch that makes this change is as
follows: (http://coccinelle.lip6.fr/)
// <smpl>
@@
expression pdev,res,n,e,e1;
expression ret != 0;
identifier l;
@@
- res = platform_get_resource(pdev, IORESOURCE_MEM, n);
... when != res
- if (res == NULL) { ... \(goto l;\|return ret;\) }
... when != res
+ res = platform_get_resource(pdev, IORESOURCE_MEM, n);
e = devm_ioremap_resource(e1, res);
// </smpl>
Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>
Signed-off-by: Mark Brown <broonie@linaro.org>
2013-08-14 13:11:09 +04:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-06-27 02:07:40 +04:00
drv_data - > regs = devm_ioremap_resource ( dev , mem ) ;
if ( IS_ERR ( drv_data - > regs ) ) {
ret = PTR_ERR ( drv_data - > regs ) ;
goto err_put_master ;
}
/* request tx and rx dma */
ret = request_dma ( tx_dma , " SPI_TX_DMA " ) ;
if ( ret ) {
dev_err ( dev , " can not request SPI TX DMA channel \n " ) ;
goto err_put_master ;
}
2014-04-04 12:27:17 +04:00
set_dma_callback ( tx_dma , adi_spi_tx_dma_isr , drv_data ) ;
2013-06-27 02:07:40 +04:00
ret = request_dma ( rx_dma , " SPI_RX_DMA " ) ;
if ( ret ) {
dev_err ( dev , " can not request SPI RX DMA channel \n " ) ;
goto err_free_tx_dma ;
}
2014-04-04 12:27:17 +04:00
set_dma_callback ( drv_data - > rx_dma , adi_spi_rx_dma_isr , drv_data ) ;
2013-06-27 02:07:40 +04:00
/* request CLK, MOSI and MISO */
2014-04-04 12:27:17 +04:00
ret = peripheral_request_list ( drv_data - > pin_req , " adi-spi3 " ) ;
2013-06-27 02:07:40 +04:00
if ( ret < 0 ) {
dev_err ( dev , " can not request spi pins \n " ) ;
goto err_free_rx_dma ;
}
2014-04-04 12:27:17 +04:00
iowrite32 ( SPI_CTL_MSTR | SPI_CTL_CPHA , & drv_data - > regs - > control ) ;
iowrite32 ( 0x0000FE00 , & drv_data - > regs - > ssel ) ;
iowrite32 ( 0x0 , & drv_data - > regs - > delay ) ;
2013-06-27 02:07:40 +04:00
tasklet_init ( & drv_data - > pump_transfers ,
2014-04-04 12:27:17 +04:00
adi_spi_pump_transfers , ( unsigned long ) drv_data ) ;
2013-06-27 02:07:40 +04:00
/* register with the SPI framework */
2013-09-24 08:26:30 +04:00
ret = devm_spi_register_master ( dev , master ) ;
2013-06-27 02:07:40 +04:00
if ( ret ) {
dev_err ( dev , " can not register spi master \n " ) ;
goto err_free_peripheral ;
}
return ret ;
err_free_peripheral :
peripheral_free_list ( drv_data - > pin_req ) ;
err_free_rx_dma :
free_dma ( rx_dma ) ;
err_free_tx_dma :
free_dma ( tx_dma ) ;
err_put_master :
spi_master_put ( master ) ;
return ret ;
}
2014-04-04 12:27:17 +04:00
static int adi_spi_remove ( struct platform_device * pdev )
2013-06-27 02:07:40 +04:00
{
struct spi_master * master = platform_get_drvdata ( pdev ) ;
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = spi_master_get_devdata ( master ) ;
2013-06-27 02:07:40 +04:00
2014-04-04 12:27:17 +04:00
adi_spi_disable ( drv_data ) ;
2013-06-27 02:07:40 +04:00
peripheral_free_list ( drv_data - > pin_req ) ;
free_dma ( drv_data - > rx_dma ) ;
free_dma ( drv_data - > tx_dma ) ;
return 0 ;
}
# ifdef CONFIG_PM
2014-04-04 12:27:17 +04:00
static int adi_spi_suspend ( struct device * dev )
2013-06-27 02:07:40 +04:00
{
struct spi_master * master = dev_get_drvdata ( dev ) ;
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = spi_master_get_devdata ( master ) ;
2013-06-27 02:07:40 +04:00
spi_master_suspend ( master ) ;
2014-04-04 12:27:17 +04:00
drv_data - > control = ioread32 ( & drv_data - > regs - > control ) ;
drv_data - > ssel = ioread32 ( & drv_data - > regs - > ssel ) ;
2013-06-27 02:07:40 +04:00
2014-04-04 12:27:17 +04:00
iowrite32 ( SPI_CTL_MSTR | SPI_CTL_CPHA , & drv_data - > regs - > control ) ;
iowrite32 ( 0x0000FE00 , & drv_data - > regs - > ssel ) ;
2013-06-27 02:07:40 +04:00
dma_disable_irq ( drv_data - > rx_dma ) ;
dma_disable_irq ( drv_data - > tx_dma ) ;
return 0 ;
}
2014-04-04 12:27:17 +04:00
static int adi_spi_resume ( struct device * dev )
2013-06-27 02:07:40 +04:00
{
struct spi_master * master = dev_get_drvdata ( dev ) ;
2014-04-04 12:27:17 +04:00
struct adi_spi_master * drv_data = spi_master_get_devdata ( master ) ;
2013-06-27 02:07:40 +04:00
int ret = 0 ;
/* bootrom may modify spi and dma status when resume in spi boot mode */
disable_dma ( drv_data - > rx_dma ) ;
dma_enable_irq ( drv_data - > rx_dma ) ;
dma_enable_irq ( drv_data - > tx_dma ) ;
2014-04-04 12:27:17 +04:00
iowrite32 ( drv_data - > control , & drv_data - > regs - > control ) ;
iowrite32 ( drv_data - > ssel , & drv_data - > regs - > ssel ) ;
2013-06-27 02:07:40 +04:00
ret = spi_master_resume ( master ) ;
if ( ret ) {
free_dma ( drv_data - > rx_dma ) ;
free_dma ( drv_data - > tx_dma ) ;
}
return ret ;
}
# endif
2014-04-04 12:27:17 +04:00
static const struct dev_pm_ops adi_spi_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS ( adi_spi_suspend , adi_spi_resume )
2013-06-27 02:07:40 +04:00
} ;
2014-04-04 12:27:17 +04:00
MODULE_ALIAS ( " platform:adi-spi3 " ) ;
static struct platform_driver adi_spi_driver = {
2013-06-27 02:07:40 +04:00
. driver = {
2014-04-04 12:27:17 +04:00
. name = " adi-spi3 " ,
2013-06-27 02:07:40 +04:00
. owner = THIS_MODULE ,
2014-04-04 12:27:17 +04:00
. pm = & adi_spi_pm_ops ,
2013-06-27 02:07:40 +04:00
} ,
2014-04-04 12:27:17 +04:00
. remove = adi_spi_remove ,
2013-06-27 02:07:40 +04:00
} ;
2014-04-04 12:27:17 +04:00
module_platform_driver_probe ( adi_spi_driver , adi_spi_probe ) ;
2013-06-27 02:07:40 +04:00
MODULE_DESCRIPTION ( " Analog Devices SPI3 controller driver " ) ;
MODULE_AUTHOR ( " Scott Jiang <Scott.Jiang.Linux@gmail.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;