2010-01-20 23:49:44 +03:00
/*
* Freescale / Motorola Coldfire Queued SPI driver
*
* Copyright 2010 Steven King < sfking @ fdwdc . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* 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 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA
*
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/interrupt.h>
# include <linux/errno.h>
# include <linux/platform_device.h>
2010-07-28 07:32:46 +04:00
# include <linux/sched.h>
2010-01-20 23:49:44 +03:00
# include <linux/delay.h>
# include <linux/io.h>
# include <linux/clk.h>
# include <linux/err.h>
# include <linux/spi/spi.h>
2012-05-10 20:26:55 +04:00
# include <linux/pm_runtime.h>
2010-01-20 23:49:44 +03:00
# include <asm/coldfire.h>
2011-04-24 21:48:07 +04:00
# include <asm/mcfsim.h>
2010-01-20 23:49:44 +03:00
# include <asm/mcfqspi.h>
# define DRIVER_NAME "mcfqspi"
# define MCFQSPI_BUSCLK (MCF_BUSCLK / 2)
# define MCFQSPI_QMR 0x00
# define MCFQSPI_QMR_MSTR 0x8000
# define MCFQSPI_QMR_CPOL 0x0200
# define MCFQSPI_QMR_CPHA 0x0100
# define MCFQSPI_QDLYR 0x04
# define MCFQSPI_QDLYR_SPE 0x8000
# define MCFQSPI_QWR 0x08
# define MCFQSPI_QWR_HALT 0x8000
# define MCFQSPI_QWR_WREN 0x4000
# define MCFQSPI_QWR_CSIV 0x1000
# define MCFQSPI_QIR 0x0C
# define MCFQSPI_QIR_WCEFB 0x8000
# define MCFQSPI_QIR_ABRTB 0x4000
# define MCFQSPI_QIR_ABRTL 0x1000
# define MCFQSPI_QIR_WCEFE 0x0800
# define MCFQSPI_QIR_ABRTE 0x0400
# define MCFQSPI_QIR_SPIFE 0x0100
# define MCFQSPI_QIR_WCEF 0x0008
# define MCFQSPI_QIR_ABRT 0x0004
# define MCFQSPI_QIR_SPIF 0x0001
# define MCFQSPI_QAR 0x010
# define MCFQSPI_QAR_TXBUF 0x00
# define MCFQSPI_QAR_RXBUF 0x10
# define MCFQSPI_QAR_CMDBUF 0x20
# define MCFQSPI_QDR 0x014
# define MCFQSPI_QCR 0x014
# define MCFQSPI_QCR_CONT 0x8000
# define MCFQSPI_QCR_BITSE 0x4000
# define MCFQSPI_QCR_DT 0x2000
struct mcfqspi {
void __iomem * iobase ;
int irq ;
struct clk * clk ;
struct mcfqspi_cs_control * cs_control ;
wait_queue_head_t waitq ;
2012-05-10 20:26:55 +04:00
struct device * dev ;
2010-01-20 23:49:44 +03:00
} ;
static void mcfqspi_wr_qmr ( struct mcfqspi * mcfqspi , u16 val )
{
writew ( val , mcfqspi - > iobase + MCFQSPI_QMR ) ;
}
static void mcfqspi_wr_qdlyr ( struct mcfqspi * mcfqspi , u16 val )
{
writew ( val , mcfqspi - > iobase + MCFQSPI_QDLYR ) ;
}
static u16 mcfqspi_rd_qdlyr ( struct mcfqspi * mcfqspi )
{
return readw ( mcfqspi - > iobase + MCFQSPI_QDLYR ) ;
}
static void mcfqspi_wr_qwr ( struct mcfqspi * mcfqspi , u16 val )
{
writew ( val , mcfqspi - > iobase + MCFQSPI_QWR ) ;
}
static void mcfqspi_wr_qir ( struct mcfqspi * mcfqspi , u16 val )
{
writew ( val , mcfqspi - > iobase + MCFQSPI_QIR ) ;
}
static void mcfqspi_wr_qar ( struct mcfqspi * mcfqspi , u16 val )
{
writew ( val , mcfqspi - > iobase + MCFQSPI_QAR ) ;
}
static void mcfqspi_wr_qdr ( struct mcfqspi * mcfqspi , u16 val )
{
writew ( val , mcfqspi - > iobase + MCFQSPI_QDR ) ;
}
static u16 mcfqspi_rd_qdr ( struct mcfqspi * mcfqspi )
{
return readw ( mcfqspi - > iobase + MCFQSPI_QDR ) ;
}
static void mcfqspi_cs_select ( struct mcfqspi * mcfqspi , u8 chip_select ,
bool cs_high )
{
mcfqspi - > cs_control - > select ( mcfqspi - > cs_control , chip_select , cs_high ) ;
}
static void mcfqspi_cs_deselect ( struct mcfqspi * mcfqspi , u8 chip_select ,
bool cs_high )
{
mcfqspi - > cs_control - > deselect ( mcfqspi - > cs_control , chip_select , cs_high ) ;
}
static int mcfqspi_cs_setup ( struct mcfqspi * mcfqspi )
{
return ( mcfqspi - > cs_control & & mcfqspi - > cs_control - > setup ) ?
mcfqspi - > cs_control - > setup ( mcfqspi - > cs_control ) : 0 ;
}
static void mcfqspi_cs_teardown ( struct mcfqspi * mcfqspi )
{
if ( mcfqspi - > cs_control & & mcfqspi - > cs_control - > teardown )
mcfqspi - > cs_control - > teardown ( mcfqspi - > cs_control ) ;
}
static u8 mcfqspi_qmr_baud ( u32 speed_hz )
{
return clamp ( ( MCFQSPI_BUSCLK + speed_hz - 1 ) / speed_hz , 2u , 255u ) ;
}
static bool mcfqspi_qdlyr_spe ( struct mcfqspi * mcfqspi )
{
return mcfqspi_rd_qdlyr ( mcfqspi ) & MCFQSPI_QDLYR_SPE ;
}
static irqreturn_t mcfqspi_irq_handler ( int this_irq , void * dev_id )
{
struct mcfqspi * mcfqspi = dev_id ;
/* clear interrupt */
mcfqspi_wr_qir ( mcfqspi , MCFQSPI_QIR_SPIFE | MCFQSPI_QIR_SPIF ) ;
wake_up ( & mcfqspi - > waitq ) ;
return IRQ_HANDLED ;
}
static void mcfqspi_transfer_msg8 ( struct mcfqspi * mcfqspi , unsigned count ,
const u8 * txbuf , u8 * rxbuf )
{
unsigned i , n , offset = 0 ;
n = min ( count , 16u ) ;
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_CMDBUF ) ;
for ( i = 0 ; i < n ; + + i )
mcfqspi_wr_qdr ( mcfqspi , MCFQSPI_QCR_BITSE ) ;
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_TXBUF ) ;
if ( txbuf )
for ( i = 0 ; i < n ; + + i )
mcfqspi_wr_qdr ( mcfqspi , * txbuf + + ) ;
else
for ( i = 0 ; i < count ; + + i )
mcfqspi_wr_qdr ( mcfqspi , 0 ) ;
count - = n ;
if ( count ) {
u16 qwr = 0xf08 ;
mcfqspi_wr_qwr ( mcfqspi , 0x700 ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
do {
wait_event ( mcfqspi - > waitq , ! mcfqspi_qdlyr_spe ( mcfqspi ) ) ;
mcfqspi_wr_qwr ( mcfqspi , qwr ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
if ( rxbuf ) {
mcfqspi_wr_qar ( mcfqspi ,
MCFQSPI_QAR_RXBUF + offset ) ;
for ( i = 0 ; i < 8 ; + + i )
* rxbuf + + = mcfqspi_rd_qdr ( mcfqspi ) ;
}
n = min ( count , 8u ) ;
if ( txbuf ) {
mcfqspi_wr_qar ( mcfqspi ,
MCFQSPI_QAR_TXBUF + offset ) ;
for ( i = 0 ; i < n ; + + i )
mcfqspi_wr_qdr ( mcfqspi , * txbuf + + ) ;
}
qwr = ( offset ? 0x808 : 0 ) + ( ( n - 1 ) < < 8 ) ;
offset ^ = 8 ;
count - = n ;
} while ( count ) ;
wait_event ( mcfqspi - > waitq , ! mcfqspi_qdlyr_spe ( mcfqspi ) ) ;
mcfqspi_wr_qwr ( mcfqspi , qwr ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
if ( rxbuf ) {
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_RXBUF + offset ) ;
for ( i = 0 ; i < 8 ; + + i )
* rxbuf + + = mcfqspi_rd_qdr ( mcfqspi ) ;
offset ^ = 8 ;
}
} else {
mcfqspi_wr_qwr ( mcfqspi , ( n - 1 ) < < 8 ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
}
wait_event ( mcfqspi - > waitq , ! mcfqspi_qdlyr_spe ( mcfqspi ) ) ;
if ( rxbuf ) {
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_RXBUF + offset ) ;
for ( i = 0 ; i < n ; + + i )
* rxbuf + + = mcfqspi_rd_qdr ( mcfqspi ) ;
}
}
static void mcfqspi_transfer_msg16 ( struct mcfqspi * mcfqspi , unsigned count ,
const u16 * txbuf , u16 * rxbuf )
{
unsigned i , n , offset = 0 ;
n = min ( count , 16u ) ;
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_CMDBUF ) ;
for ( i = 0 ; i < n ; + + i )
mcfqspi_wr_qdr ( mcfqspi , MCFQSPI_QCR_BITSE ) ;
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_TXBUF ) ;
if ( txbuf )
for ( i = 0 ; i < n ; + + i )
mcfqspi_wr_qdr ( mcfqspi , * txbuf + + ) ;
else
for ( i = 0 ; i < count ; + + i )
mcfqspi_wr_qdr ( mcfqspi , 0 ) ;
count - = n ;
if ( count ) {
u16 qwr = 0xf08 ;
mcfqspi_wr_qwr ( mcfqspi , 0x700 ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
do {
wait_event ( mcfqspi - > waitq , ! mcfqspi_qdlyr_spe ( mcfqspi ) ) ;
mcfqspi_wr_qwr ( mcfqspi , qwr ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
if ( rxbuf ) {
mcfqspi_wr_qar ( mcfqspi ,
MCFQSPI_QAR_RXBUF + offset ) ;
for ( i = 0 ; i < 8 ; + + i )
* rxbuf + + = mcfqspi_rd_qdr ( mcfqspi ) ;
}
n = min ( count , 8u ) ;
if ( txbuf ) {
mcfqspi_wr_qar ( mcfqspi ,
MCFQSPI_QAR_TXBUF + offset ) ;
for ( i = 0 ; i < n ; + + i )
mcfqspi_wr_qdr ( mcfqspi , * txbuf + + ) ;
}
qwr = ( offset ? 0x808 : 0x000 ) + ( ( n - 1 ) < < 8 ) ;
offset ^ = 8 ;
count - = n ;
} while ( count ) ;
wait_event ( mcfqspi - > waitq , ! mcfqspi_qdlyr_spe ( mcfqspi ) ) ;
mcfqspi_wr_qwr ( mcfqspi , qwr ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
if ( rxbuf ) {
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_RXBUF + offset ) ;
for ( i = 0 ; i < 8 ; + + i )
* rxbuf + + = mcfqspi_rd_qdr ( mcfqspi ) ;
offset ^ = 8 ;
}
} else {
mcfqspi_wr_qwr ( mcfqspi , ( n - 1 ) < < 8 ) ;
mcfqspi_wr_qdlyr ( mcfqspi , MCFQSPI_QDLYR_SPE ) ;
}
wait_event ( mcfqspi - > waitq , ! mcfqspi_qdlyr_spe ( mcfqspi ) ) ;
if ( rxbuf ) {
mcfqspi_wr_qar ( mcfqspi , MCFQSPI_QAR_RXBUF + offset ) ;
for ( i = 0 ; i < n ; + + i )
* rxbuf + + = mcfqspi_rd_qdr ( mcfqspi ) ;
}
}
2012-05-10 20:26:55 +04:00
static int mcfqspi_transfer_one_message ( struct spi_master * master ,
struct spi_message * msg )
2010-01-20 23:49:44 +03:00
{
2012-05-10 20:26:55 +04:00
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
struct spi_device * spi = msg - > spi ;
struct spi_transfer * t ;
int status = 0 ;
list_for_each_entry ( t , & msg - > transfers , transfer_list ) {
bool cs_high = spi - > mode & SPI_CS_HIGH ;
u16 qmr = MCFQSPI_QMR_MSTR ;
if ( t - > bits_per_word )
qmr | = t - > bits_per_word < < 10 ;
else
qmr | = spi - > bits_per_word < < 10 ;
if ( spi - > mode & SPI_CPHA )
qmr | = MCFQSPI_QMR_CPHA ;
if ( spi - > mode & SPI_CPOL )
qmr | = MCFQSPI_QMR_CPOL ;
if ( t - > speed_hz )
qmr | = mcfqspi_qmr_baud ( t - > speed_hz ) ;
else
qmr | = mcfqspi_qmr_baud ( spi - > max_speed_hz ) ;
mcfqspi_wr_qmr ( mcfqspi , qmr ) ;
mcfqspi_cs_select ( mcfqspi , spi - > chip_select , cs_high ) ;
mcfqspi_wr_qir ( mcfqspi , MCFQSPI_QIR_SPIFE ) ;
if ( ( t - > bits_per_word ? t - > bits_per_word :
spi - > bits_per_word ) = = 8 )
mcfqspi_transfer_msg8 ( mcfqspi , t - > len , t - > tx_buf ,
t - > rx_buf ) ;
else
mcfqspi_transfer_msg16 ( mcfqspi , t - > len / 2 , t - > tx_buf ,
t - > rx_buf ) ;
mcfqspi_wr_qir ( mcfqspi , 0 ) ;
if ( t - > delay_usecs )
udelay ( t - > delay_usecs ) ;
if ( t - > cs_change ) {
if ( ! list_is_last ( & t - > transfer_list , & msg - > transfers ) )
mcfqspi_cs_deselect ( mcfqspi , spi - > chip_select ,
cs_high ) ;
} else {
if ( list_is_last ( & t - > transfer_list , & msg - > transfers ) )
mcfqspi_cs_deselect ( mcfqspi , spi - > chip_select ,
cs_high ) ;
2010-01-20 23:49:44 +03:00
}
2012-05-10 20:26:55 +04:00
msg - > actual_length + = t - > len ;
2010-01-20 23:49:44 +03:00
}
2012-05-10 20:26:55 +04:00
msg - > status = status ;
spi_finalize_current_message ( master ) ;
return status ;
2010-01-20 23:49:44 +03:00
}
2012-05-10 20:26:55 +04:00
static int mcfqspi_prepare_transfer_hw ( struct spi_master * master )
2010-01-20 23:49:44 +03:00
{
2012-05-10 20:26:55 +04:00
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
2010-01-20 23:49:44 +03:00
2012-05-10 20:26:55 +04:00
pm_runtime_get_sync ( mcfqspi - > dev ) ;
return 0 ;
}
static int mcfqspi_unprepare_transfer_hw ( struct spi_master * master )
{
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
pm_runtime_put_sync ( mcfqspi - > dev ) ;
2010-01-20 23:49:44 +03:00
return 0 ;
}
static int mcfqspi_setup ( struct spi_device * spi )
{
if ( ( spi - > bits_per_word < 8 ) | | ( spi - > bits_per_word > 16 ) ) {
dev_dbg ( & spi - > dev , " %d bits per word is not supported \n " ,
spi - > bits_per_word ) ;
return - EINVAL ;
}
if ( spi - > chip_select > = spi - > master - > num_chipselect ) {
dev_dbg ( & spi - > dev , " %d chip select is out of range \n " ,
spi - > chip_select ) ;
return - EINVAL ;
}
mcfqspi_cs_deselect ( spi_master_get_devdata ( spi - > master ) ,
spi - > chip_select , spi - > mode & SPI_CS_HIGH ) ;
dev_dbg ( & spi - > dev ,
" bits per word %d, chip select %d, speed %d KHz \n " ,
spi - > bits_per_word , spi - > chip_select ,
( MCFQSPI_BUSCLK / mcfqspi_qmr_baud ( spi - > max_speed_hz ) )
/ 1000 ) ;
return 0 ;
}
2012-12-07 20:57:14 +04:00
static int mcfqspi_probe ( struct platform_device * pdev )
2010-01-20 23:49:44 +03:00
{
struct spi_master * master ;
struct mcfqspi * mcfqspi ;
struct resource * res ;
struct mcfqspi_platform_data * pdata ;
int status ;
master = spi_alloc_master ( & pdev - > dev , sizeof ( * mcfqspi ) ) ;
if ( master = = NULL ) {
dev_dbg ( & pdev - > dev , " spi_alloc_master failed \n " ) ;
return - ENOMEM ;
}
mcfqspi = spi_master_get_devdata ( master ) ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res ) {
dev_dbg ( & pdev - > dev , " platform_get_resource failed \n " ) ;
status = - ENXIO ;
goto fail0 ;
}
if ( ! request_mem_region ( res - > start , resource_size ( res ) , pdev - > name ) ) {
dev_dbg ( & pdev - > dev , " request_mem_region failed \n " ) ;
status = - EBUSY ;
goto fail0 ;
}
mcfqspi - > iobase = ioremap ( res - > start , resource_size ( res ) ) ;
if ( ! mcfqspi - > iobase ) {
dev_dbg ( & pdev - > dev , " ioremap failed \n " ) ;
status = - ENOMEM ;
goto fail1 ;
}
mcfqspi - > irq = platform_get_irq ( pdev , 0 ) ;
if ( mcfqspi - > irq < 0 ) {
dev_dbg ( & pdev - > dev , " platform_get_irq failed \n " ) ;
status = - ENXIO ;
goto fail2 ;
}
2011-10-22 13:56:55 +04:00
status = request_irq ( mcfqspi - > irq , mcfqspi_irq_handler , 0 ,
2010-01-20 23:49:44 +03:00
pdev - > name , mcfqspi ) ;
if ( status ) {
dev_dbg ( & pdev - > dev , " request_irq failed \n " ) ;
goto fail2 ;
}
mcfqspi - > clk = clk_get ( & pdev - > dev , " qspi_clk " ) ;
if ( IS_ERR ( mcfqspi - > clk ) ) {
dev_dbg ( & pdev - > dev , " clk_get failed \n " ) ;
status = PTR_ERR ( mcfqspi - > clk ) ;
goto fail3 ;
}
clk_enable ( mcfqspi - > clk ) ;
pdata = pdev - > dev . platform_data ;
if ( ! pdata ) {
dev_dbg ( & pdev - > dev , " platform data is missing \n " ) ;
2012-05-10 20:26:55 +04:00
goto fail4 ;
2010-01-20 23:49:44 +03:00
}
master - > bus_num = pdata - > bus_num ;
master - > num_chipselect = pdata - > num_chipselect ;
mcfqspi - > cs_control = pdata - > cs_control ;
status = mcfqspi_cs_setup ( mcfqspi ) ;
if ( status ) {
dev_dbg ( & pdev - > dev , " error initializing cs_control \n " ) ;
2012-05-10 20:26:55 +04:00
goto fail4 ;
2010-01-20 23:49:44 +03:00
}
2012-05-10 20:26:55 +04:00
init_waitqueue_head ( & mcfqspi - > waitq ) ;
mcfqspi - > dev = & pdev - > dev ;
2010-01-20 23:49:44 +03:00
master - > mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA ;
master - > setup = mcfqspi_setup ;
2012-05-10 20:26:55 +04:00
master - > transfer_one_message = mcfqspi_transfer_one_message ;
master - > prepare_transfer_hardware = mcfqspi_prepare_transfer_hw ;
master - > unprepare_transfer_hardware = mcfqspi_unprepare_transfer_hw ;
2010-01-20 23:49:44 +03:00
platform_set_drvdata ( pdev , master ) ;
status = spi_register_master ( master ) ;
if ( status ) {
dev_dbg ( & pdev - > dev , " spi_register_master failed \n " ) ;
2012-05-10 20:26:55 +04:00
goto fail5 ;
2010-01-20 23:49:44 +03:00
}
2012-05-10 20:26:55 +04:00
pm_runtime_enable ( mcfqspi - > dev ) ;
2010-01-20 23:49:44 +03:00
dev_info ( & pdev - > dev , " Coldfire QSPI bus driver \n " ) ;
return 0 ;
fail5 :
2012-05-10 20:26:55 +04:00
mcfqspi_cs_teardown ( mcfqspi ) ;
2010-01-20 23:49:44 +03:00
fail4 :
clk_disable ( mcfqspi - > clk ) ;
clk_put ( mcfqspi - > clk ) ;
fail3 :
free_irq ( mcfqspi - > irq , mcfqspi ) ;
fail2 :
iounmap ( mcfqspi - > iobase ) ;
fail1 :
release_mem_region ( res - > start , resource_size ( res ) ) ;
fail0 :
spi_master_put ( master ) ;
dev_dbg ( & pdev - > dev , " Coldfire QSPI probe failed \n " ) ;
return status ;
}
2012-12-07 20:57:14 +04:00
static int mcfqspi_remove ( struct platform_device * pdev )
2010-01-20 23:49:44 +03:00
{
struct spi_master * master = platform_get_drvdata ( pdev ) ;
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
struct resource * res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2012-05-10 20:26:55 +04:00
pm_runtime_disable ( mcfqspi - > dev ) ;
2010-01-20 23:49:44 +03:00
/* disable the hardware (set the baud rate to 0) */
mcfqspi_wr_qmr ( mcfqspi , MCFQSPI_QMR_MSTR ) ;
platform_set_drvdata ( pdev , NULL ) ;
mcfqspi_cs_teardown ( mcfqspi ) ;
clk_disable ( mcfqspi - > clk ) ;
clk_put ( mcfqspi - > clk ) ;
free_irq ( mcfqspi - > irq , mcfqspi ) ;
iounmap ( mcfqspi - > iobase ) ;
release_mem_region ( res - > start , resource_size ( res ) ) ;
spi_unregister_master ( master ) ;
return 0 ;
}
2012-05-10 20:26:55 +04:00
# ifdef CONFIG_PM_SLEEP
2010-01-20 23:49:44 +03:00
static int mcfqspi_suspend ( struct device * dev )
{
2012-08-17 07:26:00 +04:00
struct spi_master * master = dev_get_drvdata ( dev ) ;
2012-05-10 20:26:55 +04:00
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
spi_master_suspend ( master ) ;
2010-01-20 23:49:44 +03:00
clk_disable ( mcfqspi - > clk ) ;
return 0 ;
}
static int mcfqspi_resume ( struct device * dev )
{
2012-08-17 07:26:00 +04:00
struct spi_master * master = dev_get_drvdata ( dev ) ;
2012-05-10 20:26:55 +04:00
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
spi_master_resume ( master ) ;
2010-01-20 23:49:44 +03:00
clk_enable ( mcfqspi - > clk ) ;
return 0 ;
}
2012-05-10 20:26:55 +04:00
# endif
2010-01-20 23:49:44 +03:00
2012-05-10 20:26:55 +04:00
# ifdef CONFIG_PM_RUNTIME
static int mcfqspi_runtime_suspend ( struct device * dev )
{
struct mcfqspi * mcfqspi = platform_get_drvdata ( to_platform_device ( dev ) ) ;
2010-01-20 23:49:44 +03:00
2012-05-10 20:26:55 +04:00
clk_disable ( mcfqspi - > clk ) ;
return 0 ;
}
static int mcfqspi_runtime_resume ( struct device * dev )
{
struct mcfqspi * mcfqspi = platform_get_drvdata ( to_platform_device ( dev ) ) ;
clk_enable ( mcfqspi - > clk ) ;
return 0 ;
}
2010-01-20 23:49:44 +03:00
# endif
2012-05-10 20:26:55 +04:00
static const struct dev_pm_ops mcfqspi_pm = {
SET_SYSTEM_SLEEP_PM_OPS ( mcfqspi_suspend , mcfqspi_resume )
SET_RUNTIME_PM_OPS ( mcfqspi_runtime_suspend , mcfqspi_runtime_resume ,
NULL )
} ;
2010-01-20 23:49:44 +03:00
static struct platform_driver mcfqspi_driver = {
. driver . name = DRIVER_NAME ,
. driver . owner = THIS_MODULE ,
2012-05-10 20:26:55 +04:00
. driver . pm = & mcfqspi_pm ,
2011-10-05 21:29:49 +04:00
. probe = mcfqspi_probe ,
2012-12-07 20:57:14 +04:00
. remove = mcfqspi_remove ,
2010-01-20 23:49:44 +03:00
} ;
2011-10-05 21:29:49 +04:00
module_platform_driver ( mcfqspi_driver ) ;
2010-01-20 23:49:44 +03:00
MODULE_AUTHOR ( " Steven King <sfking@fdwdc.com> " ) ;
MODULE_DESCRIPTION ( " Coldfire QSPI Controller Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform: " DRIVER_NAME ) ;