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 .
*/
# 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 ;
} ;
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 )
{
2014-03-09 10:11:10 +04:00
return ( mcfqspi - > cs_control - > setup ) ?
2010-01-20 23:49:44 +03:00
mcfqspi - > cs_control - > setup ( mcfqspi - > cs_control ) : 0 ;
}
static void mcfqspi_cs_teardown ( struct mcfqspi * mcfqspi )
{
2014-03-09 10:11:10 +04:00
if ( mcfqspi - > cs_control - > teardown )
2010-01-20 23:49:44 +03:00
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 ) ;
}
}
2014-02-14 05:55:55 +04:00
static void mcfqspi_set_cs ( struct spi_device * spi , bool enable )
2010-01-20 23:49:44 +03:00
{
2014-02-14 05:55:55 +04:00
struct mcfqspi * mcfqspi = spi_master_get_devdata ( spi - > master ) ;
bool cs_high = spi - > mode & SPI_CS_HIGH ;
2012-05-10 20:26:55 +04:00
2014-02-14 05:55:55 +04:00
if ( enable )
2012-05-10 20:26:55 +04:00
mcfqspi_cs_select ( mcfqspi , spi - > chip_select , cs_high ) ;
2014-02-14 05:55:55 +04:00
else
mcfqspi_cs_deselect ( mcfqspi , spi - > chip_select , cs_high ) ;
}
2012-05-10 20:26:55 +04:00
2014-02-14 05:55:55 +04:00
static int mcfqspi_transfer_one ( struct spi_master * master ,
struct spi_device * spi ,
struct spi_transfer * t )
{
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
u16 qmr = MCFQSPI_QMR_MSTR ;
qmr | = t - > bits_per_word < < 10 ;
if ( spi - > mode & SPI_CPHA )
qmr | = MCFQSPI_QMR_CPHA ;
if ( spi - > mode & SPI_CPOL )
qmr | = MCFQSPI_QMR_CPOL ;
2014-03-20 18:59:06 +04:00
qmr | = mcfqspi_qmr_baud ( t - > speed_hz ) ;
2014-02-14 05:55:55 +04:00
mcfqspi_wr_qmr ( mcfqspi , qmr ) ;
2012-05-10 20:26:55 +04:00
2014-02-14 05:55:55 +04:00
mcfqspi_wr_qir ( mcfqspi , MCFQSPI_QIR_SPIFE ) ;
if ( t - > 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 ) ;
2012-05-10 20:26:55 +04:00
2014-02-14 05:55:55 +04:00
return 0 ;
2010-01-20 23:49:44 +03:00
}
static int mcfqspi_setup ( struct spi_device * spi )
{
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 ;
2013-07-30 11:58:59 +04:00
pdata = dev_get_platdata ( & pdev - > dev ) ;
2013-05-16 09:11:32 +04:00
if ( ! pdata ) {
dev_dbg ( & pdev - > dev , " platform data is missing \n " ) ;
return - ENOENT ;
}
2014-03-09 10:11:10 +04:00
if ( ! pdata - > cs_control ) {
dev_dbg ( & pdev - > dev , " pdata->cs_control is NULL \n " ) ;
return - EINVAL ;
}
2010-01-20 23:49:44 +03:00
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 ) ;
2013-12-04 09:10:10 +04:00
mcfqspi - > iobase = devm_ioremap_resource ( & pdev - > dev , res ) ;
if ( IS_ERR ( mcfqspi - > iobase ) ) {
status = PTR_ERR ( mcfqspi - > iobase ) ;
2010-01-20 23:49:44 +03:00
goto fail0 ;
}
mcfqspi - > irq = platform_get_irq ( pdev , 0 ) ;
if ( mcfqspi - > irq < 0 ) {
dev_dbg ( & pdev - > dev , " platform_get_irq failed \n " ) ;
status = - ENXIO ;
2013-12-04 09:10:10 +04:00
goto fail0 ;
2010-01-20 23:49:44 +03:00
}
2013-12-04 09:10:10 +04:00
status = devm_request_irq ( & pdev - > dev , mcfqspi - > irq , mcfqspi_irq_handler ,
0 , pdev - > name , mcfqspi ) ;
2010-01-20 23:49:44 +03:00
if ( status ) {
dev_dbg ( & pdev - > dev , " request_irq failed \n " ) ;
2013-12-04 09:10:10 +04:00
goto fail0 ;
2010-01-20 23:49:44 +03:00
}
2013-12-04 09:10:10 +04:00
mcfqspi - > clk = devm_clk_get ( & pdev - > dev , " qspi_clk " ) ;
2010-01-20 23:49:44 +03:00
if ( IS_ERR ( mcfqspi - > clk ) ) {
dev_dbg ( & pdev - > dev , " clk_get failed \n " ) ;
status = PTR_ERR ( mcfqspi - > clk ) ;
2013-12-04 09:10:10 +04:00
goto fail0 ;
2010-01-20 23:49:44 +03:00
}
clk_enable ( mcfqspi - > clk ) ;
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 " ) ;
2013-12-04 09:10:10 +04:00
goto fail1 ;
2010-01-20 23:49:44 +03:00
}
2012-05-10 20:26:55 +04:00
init_waitqueue_head ( & mcfqspi - > waitq ) ;
2010-01-20 23:49:44 +03:00
master - > mode_bits = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA ;
2013-05-22 06:36:35 +04:00
master - > bits_per_word_mask = SPI_BPW_RANGE_MASK ( 8 , 16 ) ;
2010-01-20 23:49:44 +03:00
master - > setup = mcfqspi_setup ;
2014-02-14 05:55:55 +04:00
master - > set_cs = mcfqspi_set_cs ;
master - > transfer_one = mcfqspi_transfer_one ;
2013-07-28 18:34:21 +04:00
master - > auto_runtime_pm = true ;
2010-01-20 23:49:44 +03:00
platform_set_drvdata ( pdev , master ) ;
2013-12-04 09:10:10 +04:00
status = devm_spi_register_master ( & pdev - > dev , master ) ;
2010-01-20 23:49:44 +03:00
if ( status ) {
dev_dbg ( & pdev - > dev , " spi_register_master failed \n " ) ;
2013-12-04 09:10:10 +04:00
goto fail2 ;
2010-01-20 23:49:44 +03:00
}
2014-02-14 05:54:25 +04:00
pm_runtime_enable ( & pdev - > dev ) ;
2012-05-10 20:26:55 +04:00
2010-01-20 23:49:44 +03:00
dev_info ( & pdev - > dev , " Coldfire QSPI bus driver \n " ) ;
return 0 ;
fail2 :
2013-12-04 09:10:10 +04:00
mcfqspi_cs_teardown ( mcfqspi ) ;
2010-01-20 23:49:44 +03:00
fail1 :
2013-12-04 09:10:10 +04:00
clk_disable ( mcfqspi - > clk ) ;
2010-01-20 23:49:44 +03:00
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 ) ;
2014-02-14 05:54:25 +04:00
pm_runtime_disable ( & pdev - > 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 ) ;
mcfqspi_cs_teardown ( mcfqspi ) ;
clk_disable ( mcfqspi - > clk ) ;
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 ) ;
2014-02-26 05:47:55 +04:00
int ret ;
2012-05-10 20:26:55 +04:00
2014-02-26 05:47:55 +04:00
ret = spi_master_suspend ( master ) ;
if ( ret )
return ret ;
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 ) ;
2010-01-20 23:49:44 +03:00
clk_enable ( mcfqspi - > clk ) ;
2014-02-26 05:47:55 +04:00
return spi_master_resume ( master ) ;
2010-01-20 23:49:44 +03:00
}
2012-05-10 20:26:55 +04:00
# endif
2010-01-20 23:49:44 +03:00
2014-12-13 02:41:15 +03:00
# ifdef CONFIG_PM
2012-05-10 20:26:55 +04:00
static int mcfqspi_runtime_suspend ( struct device * dev )
{
2014-02-14 05:53:00 +04:00
struct spi_master * master = dev_get_drvdata ( dev ) ;
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
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 )
{
2014-02-14 05:53:00 +04:00
struct spi_master * master = dev_get_drvdata ( dev ) ;
struct mcfqspi * mcfqspi = spi_master_get_devdata ( master ) ;
2012-05-10 20:26:55 +04:00
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 ) ;