2013-08-20 18:55:48 +05:30
/*
* TI QSPI driver
*
* Copyright ( C ) 2013 Texas Instruments Incorporated - http : //www.ti.com
* Author : Sourav Poddar < sourav . poddar @ ti . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GPLv2 .
*
* 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/init.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/delay.h>
# include <linux/dma-mapping.h>
# include <linux/dmaengine.h>
# include <linux/omap-dma.h>
# include <linux/platform_device.h>
# include <linux/err.h>
# include <linux/clk.h>
# include <linux/io.h>
# include <linux/slab.h>
# include <linux/pm_runtime.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/pinctrl/consumer.h>
2015-12-11 09:39:57 +05:30
# include <linux/mfd/syscon.h>
# include <linux/regmap.h>
2013-08-20 18:55:48 +05:30
# include <linux/spi/spi.h>
struct ti_qspi_regs {
u32 clkctrl ;
} ;
struct ti_qspi {
/* list synchronization */
struct mutex list_lock ;
struct spi_master * master ;
void __iomem * base ;
2013-12-06 19:54:43 +05:30
void __iomem * mmap_base ;
2015-12-11 09:39:57 +05:30
struct regmap * ctrl_base ;
unsigned int ctrl_reg ;
2013-08-20 18:55:48 +05:30
struct clk * fclk ;
struct device * dev ;
struct ti_qspi_regs ctx_reg ;
u32 spi_max_frequency ;
u32 cmd ;
u32 dc ;
2013-12-06 19:54:43 +05:30
2015-12-11 09:39:57 +05:30
bool mmap_enabled ;
2013-08-20 18:55:48 +05:30
} ;
# define QSPI_PID (0x0)
# define QSPI_SYSCONFIG (0x10)
# define QSPI_SPI_CLOCK_CNTRL_REG (0x40)
# define QSPI_SPI_DC_REG (0x44)
# define QSPI_SPI_CMD_REG (0x48)
# define QSPI_SPI_STATUS_REG (0x4c)
# define QSPI_SPI_DATA_REG (0x50)
2015-12-11 09:39:57 +05:30
# define QSPI_SPI_SETUP_REG(n) ((0x54 + 4 * n))
2013-08-20 18:55:48 +05:30
# define QSPI_SPI_SWITCH_REG (0x64)
# define QSPI_SPI_DATA_REG_1 (0x68)
# define QSPI_SPI_DATA_REG_2 (0x6c)
# define QSPI_SPI_DATA_REG_3 (0x70)
# define QSPI_COMPLETION_TIMEOUT msecs_to_jiffies(2000)
# define QSPI_FCLK 192000000
/* Clock Control */
# define QSPI_CLK_EN (1 << 31)
# define QSPI_CLK_DIV_MAX 0xffff
/* Command */
# define QSPI_EN_CS(n) (n << 28)
# define QSPI_WLEN(n) ((n - 1) << 19)
# define QSPI_3_PIN (1 << 18)
# define QSPI_RD_SNGL (1 << 16)
# define QSPI_WR_SNGL (2 << 16)
# define QSPI_RD_DUAL (3 << 16)
# define QSPI_RD_QUAD (7 << 16)
# define QSPI_INVAL (4 << 16)
# define QSPI_FLEN(n) ((n - 1) << 0)
2015-08-20 16:00:59 +05:30
# define QSPI_WLEN_MAX_BITS 128
# define QSPI_WLEN_MAX_BYTES 16
2013-08-20 18:55:48 +05:30
/* STATUS REGISTER */
2015-02-18 00:33:51 +05:30
# define BUSY 0x01
2013-08-20 18:55:48 +05:30
# define WC 0x02
/* Device Control */
# define QSPI_DD(m, n) (m << (3 + n * 8))
# define QSPI_CKPHA(n) (1 << (2 + n * 8))
# define QSPI_CSPOL(n) (1 << (1 + n * 8))
# define QSPI_CKPOL(n) (1 << (n * 8))
# define QSPI_FRAME 4096
# define QSPI_AUTOSUSPEND_TIMEOUT 2000
2015-12-11 09:39:57 +05:30
# define MEM_CS_EN(n) ((n + 1) << 8)
# define MEM_CS_MASK (7 << 8)
# define MM_SWITCH 0x1
# define QSPI_SETUP_RD_NORMAL (0x0 << 12)
# define QSPI_SETUP_RD_DUAL (0x1 << 12)
# define QSPI_SETUP_RD_QUAD (0x3 << 12)
# define QSPI_SETUP_ADDR_SHIFT 8
# define QSPI_SETUP_DUMMY_SHIFT 10
2013-08-20 18:55:48 +05:30
static inline unsigned long ti_qspi_read ( struct ti_qspi * qspi ,
unsigned long reg )
{
return readl ( qspi - > base + reg ) ;
}
static inline void ti_qspi_write ( struct ti_qspi * qspi ,
unsigned long val , unsigned long reg )
{
writel ( val , qspi - > base + reg ) ;
}
static int ti_qspi_setup ( struct spi_device * spi )
{
struct ti_qspi * qspi = spi_master_get_devdata ( spi - > master ) ;
struct ti_qspi_regs * ctx_reg = & qspi - > ctx_reg ;
int clk_div = 0 , ret ;
u32 clk_ctrl_reg , clk_rate , clk_mask ;
if ( spi - > master - > busy ) {
dev_dbg ( qspi - > dev , " master busy doing other trasnfers \n " ) ;
return - EBUSY ;
}
if ( ! qspi - > spi_max_frequency ) {
dev_err ( qspi - > dev , " spi max frequency not defined \n " ) ;
return - EINVAL ;
}
clk_rate = clk_get_rate ( qspi - > fclk ) ;
clk_div = DIV_ROUND_UP ( clk_rate , qspi - > spi_max_frequency ) - 1 ;
if ( clk_div < 0 ) {
dev_dbg ( qspi - > dev , " clock divider < 0, using /1 divider \n " ) ;
return - EINVAL ;
}
if ( clk_div > QSPI_CLK_DIV_MAX ) {
dev_dbg ( qspi - > dev , " clock divider >%d , using /%d divider \n " ,
QSPI_CLK_DIV_MAX , QSPI_CLK_DIV_MAX + 1 ) ;
return - EINVAL ;
}
dev_dbg ( qspi - > dev , " hz: %d, clock divider %d \n " ,
qspi - > spi_max_frequency , clk_div ) ;
ret = pm_runtime_get_sync ( qspi - > dev ) ;
2013-11-19 18:37:15 +05:30
if ( ret < 0 ) {
2013-08-20 18:55:48 +05:30
dev_err ( qspi - > dev , " pm_runtime_get_sync() failed \n " ) ;
return ret ;
}
clk_ctrl_reg = ti_qspi_read ( qspi , QSPI_SPI_CLOCK_CNTRL_REG ) ;
clk_ctrl_reg & = ~ QSPI_CLK_EN ;
/* disable SCLK */
ti_qspi_write ( qspi , clk_ctrl_reg , QSPI_SPI_CLOCK_CNTRL_REG ) ;
/* enable SCLK */
clk_mask = QSPI_CLK_EN | clk_div ;
ti_qspi_write ( qspi , clk_mask , QSPI_SPI_CLOCK_CNTRL_REG ) ;
ctx_reg - > clkctrl = clk_mask ;
pm_runtime_mark_last_busy ( qspi - > dev ) ;
ret = pm_runtime_put_autosuspend ( qspi - > dev ) ;
if ( ret < 0 ) {
dev_err ( qspi - > dev , " pm_runtime_put_autosuspend() failed \n " ) ;
return ret ;
}
return 0 ;
}
static void ti_qspi_restore_ctx ( struct ti_qspi * qspi )
{
struct ti_qspi_regs * ctx_reg = & qspi - > ctx_reg ;
ti_qspi_write ( qspi , ctx_reg - > clkctrl , QSPI_SPI_CLOCK_CNTRL_REG ) ;
}
2015-02-18 00:33:51 +05:30
static inline u32 qspi_is_busy ( struct ti_qspi * qspi )
{
u32 stat ;
unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT ;
stat = ti_qspi_read ( qspi , QSPI_SPI_STATUS_REG ) ;
while ( ( stat & BUSY ) & & time_after ( timeout , jiffies ) ) {
cpu_relax ( ) ;
stat = ti_qspi_read ( qspi , QSPI_SPI_STATUS_REG ) ;
}
WARN ( stat & BUSY , " qspi busy \n " ) ;
return stat & BUSY ;
}
2015-10-13 15:51:05 +05:30
static inline int ti_qspi_poll_wc ( struct ti_qspi * qspi )
{
u32 stat ;
unsigned long timeout = jiffies + QSPI_COMPLETION_TIMEOUT ;
do {
stat = ti_qspi_read ( qspi , QSPI_SPI_STATUS_REG ) ;
if ( stat & WC )
return 0 ;
cpu_relax ( ) ;
} while ( time_after ( timeout , jiffies ) ) ;
stat = ti_qspi_read ( qspi , QSPI_SPI_STATUS_REG ) ;
if ( stat & WC )
return 0 ;
return - ETIMEDOUT ;
}
2013-08-20 18:55:48 +05:30
static int qspi_write_msg ( struct ti_qspi * qspi , struct spi_transfer * t )
{
2015-08-20 16:00:59 +05:30
int wlen , count , xfer_len ;
2013-08-20 18:55:48 +05:30
unsigned int cmd ;
const u8 * txbuf ;
2015-08-20 16:00:59 +05:30
u32 data ;
2013-08-20 18:55:48 +05:30
txbuf = t - > tx_buf ;
cmd = qspi - > cmd | QSPI_WR_SNGL ;
count = t - > len ;
2014-01-12 14:40:22 +08:00
wlen = t - > bits_per_word > > 3 ; /* in bytes */
2015-08-20 16:00:59 +05:30
xfer_len = wlen ;
2013-08-20 18:55:48 +05:30
while ( count ) {
2015-02-18 00:33:51 +05:30
if ( qspi_is_busy ( qspi ) )
return - EBUSY ;
2013-08-20 18:55:48 +05:30
switch ( wlen ) {
2014-01-12 14:40:22 +08:00
case 1 :
2013-08-20 18:55:48 +05:30
dev_dbg ( qspi - > dev , " tx cmd %08x dc %08x data %02x \n " ,
cmd , qspi - > dc , * txbuf ) ;
2015-08-20 16:00:59 +05:30
if ( count > = QSPI_WLEN_MAX_BYTES ) {
u32 * txp = ( u32 * ) txbuf ;
data = cpu_to_be32 ( * txp + + ) ;
writel ( data , qspi - > base +
QSPI_SPI_DATA_REG_3 ) ;
data = cpu_to_be32 ( * txp + + ) ;
writel ( data , qspi - > base +
QSPI_SPI_DATA_REG_2 ) ;
data = cpu_to_be32 ( * txp + + ) ;
writel ( data , qspi - > base +
QSPI_SPI_DATA_REG_1 ) ;
data = cpu_to_be32 ( * txp + + ) ;
writel ( data , qspi - > base +
QSPI_SPI_DATA_REG ) ;
xfer_len = QSPI_WLEN_MAX_BYTES ;
cmd | = QSPI_WLEN ( QSPI_WLEN_MAX_BITS ) ;
} else {
writeb ( * txbuf , qspi - > base + QSPI_SPI_DATA_REG ) ;
cmd = qspi - > cmd | QSPI_WR_SNGL ;
xfer_len = wlen ;
cmd | = QSPI_WLEN ( wlen ) ;
}
2013-08-20 18:55:48 +05:30
break ;
2014-01-12 14:40:22 +08:00
case 2 :
2013-08-20 18:55:48 +05:30
dev_dbg ( qspi - > dev , " tx cmd %08x dc %08x data %04x \n " ,
cmd , qspi - > dc , * txbuf ) ;
writew ( * ( ( u16 * ) txbuf ) , qspi - > base + QSPI_SPI_DATA_REG ) ;
break ;
2014-01-12 14:40:22 +08:00
case 4 :
2013-08-20 18:55:48 +05:30
dev_dbg ( qspi - > dev , " tx cmd %08x dc %08x data %08x \n " ,
cmd , qspi - > dc , * txbuf ) ;
writel ( * ( ( u32 * ) txbuf ) , qspi - > base + QSPI_SPI_DATA_REG ) ;
break ;
}
2014-01-12 14:40:22 +08:00
ti_qspi_write ( qspi , cmd , QSPI_SPI_CMD_REG ) ;
2015-10-13 15:51:05 +05:30
if ( ti_qspi_poll_wc ( qspi ) ) {
2014-01-12 14:40:22 +08:00
dev_err ( qspi - > dev , " write timed out \n " ) ;
return - ETIMEDOUT ;
}
2015-08-20 16:00:59 +05:30
txbuf + = xfer_len ;
count - = xfer_len ;
2013-08-20 18:55:48 +05:30
}
return 0 ;
}
static int qspi_read_msg ( struct ti_qspi * qspi , struct spi_transfer * t )
{
2015-02-05 10:03:42 -05:00
int wlen , count ;
2013-08-20 18:55:48 +05:30
unsigned int cmd ;
u8 * rxbuf ;
rxbuf = t - > rx_buf ;
2013-08-23 15:12:16 +05:30
cmd = qspi - > cmd ;
switch ( t - > rx_nbits ) {
case SPI_NBITS_DUAL :
cmd | = QSPI_RD_DUAL ;
break ;
case SPI_NBITS_QUAD :
cmd | = QSPI_RD_QUAD ;
break ;
default :
cmd | = QSPI_RD_SNGL ;
break ;
}
2013-08-20 18:55:48 +05:30
count = t - > len ;
2014-01-12 14:40:22 +08:00
wlen = t - > bits_per_word > > 3 ; /* in bytes */
2013-08-20 18:55:48 +05:30
while ( count ) {
dev_dbg ( qspi - > dev , " rx cmd %08x dc %08x \n " , cmd , qspi - > dc ) ;
2015-02-18 00:33:51 +05:30
if ( qspi_is_busy ( qspi ) )
return - EBUSY ;
2013-08-20 18:55:48 +05:30
ti_qspi_write ( qspi , cmd , QSPI_SPI_CMD_REG ) ;
2015-10-13 15:51:05 +05:30
if ( ti_qspi_poll_wc ( qspi ) ) {
2013-08-20 18:55:48 +05:30
dev_err ( qspi - > dev , " read timed out \n " ) ;
return - ETIMEDOUT ;
}
switch ( wlen ) {
2014-01-12 14:40:22 +08:00
case 1 :
2013-08-20 18:55:48 +05:30
* rxbuf = readb ( qspi - > base + QSPI_SPI_DATA_REG ) ;
break ;
2014-01-12 14:40:22 +08:00
case 2 :
2013-08-20 18:55:48 +05:30
* ( ( u16 * ) rxbuf ) = readw ( qspi - > base + QSPI_SPI_DATA_REG ) ;
break ;
2014-01-12 14:40:22 +08:00
case 4 :
2013-08-20 18:55:48 +05:30
* ( ( u32 * ) rxbuf ) = readl ( qspi - > base + QSPI_SPI_DATA_REG ) ;
break ;
}
2014-01-12 14:40:22 +08:00
rxbuf + = wlen ;
count - = wlen ;
2013-08-20 18:55:48 +05:30
}
return 0 ;
}
static int qspi_transfer_msg ( struct ti_qspi * qspi , struct spi_transfer * t )
{
int ret ;
if ( t - > tx_buf ) {
ret = qspi_write_msg ( qspi , t ) ;
if ( ret ) {
dev_dbg ( qspi - > dev , " Error while writing \n " ) ;
return ret ;
}
}
if ( t - > rx_buf ) {
ret = qspi_read_msg ( qspi , t ) ;
if ( ret ) {
dev_dbg ( qspi - > dev , " Error while reading \n " ) ;
return ret ;
}
}
return 0 ;
}
2015-12-11 09:39:57 +05:30
static void ti_qspi_enable_memory_map ( struct spi_device * spi )
{
struct ti_qspi * qspi = spi_master_get_devdata ( spi - > master ) ;
ti_qspi_write ( qspi , MM_SWITCH , QSPI_SPI_SWITCH_REG ) ;
if ( qspi - > ctrl_base ) {
regmap_update_bits ( qspi - > ctrl_base , qspi - > ctrl_reg ,
MEM_CS_EN ( spi - > chip_select ) ,
MEM_CS_MASK ) ;
}
qspi - > mmap_enabled = true ;
}
static void ti_qspi_disable_memory_map ( struct spi_device * spi )
{
struct ti_qspi * qspi = spi_master_get_devdata ( spi - > master ) ;
ti_qspi_write ( qspi , 0 , QSPI_SPI_SWITCH_REG ) ;
if ( qspi - > ctrl_base )
regmap_update_bits ( qspi - > ctrl_base , qspi - > ctrl_reg ,
0 , MEM_CS_MASK ) ;
qspi - > mmap_enabled = false ;
}
static void ti_qspi_setup_mmap_read ( struct spi_device * spi ,
struct spi_flash_read_message * msg )
{
struct ti_qspi * qspi = spi_master_get_devdata ( spi - > master ) ;
u32 memval = msg - > read_opcode ;
switch ( msg - > data_nbits ) {
case SPI_NBITS_QUAD :
memval | = QSPI_SETUP_RD_QUAD ;
break ;
case SPI_NBITS_DUAL :
memval | = QSPI_SETUP_RD_DUAL ;
break ;
default :
memval | = QSPI_SETUP_RD_NORMAL ;
break ;
}
memval | = ( ( msg - > addr_width - 1 ) < < QSPI_SETUP_ADDR_SHIFT |
msg - > dummy_bytes < < QSPI_SETUP_DUMMY_SHIFT ) ;
ti_qspi_write ( qspi , memval ,
QSPI_SPI_SETUP_REG ( spi - > chip_select ) ) ;
}
static int ti_qspi_spi_flash_read ( struct spi_device * spi ,
struct spi_flash_read_message * msg )
{
struct ti_qspi * qspi = spi_master_get_devdata ( spi - > master ) ;
int ret = 0 ;
mutex_lock ( & qspi - > list_lock ) ;
if ( ! qspi - > mmap_enabled )
ti_qspi_enable_memory_map ( spi ) ;
ti_qspi_setup_mmap_read ( spi , msg ) ;
memcpy_fromio ( msg - > buf , qspi - > mmap_base + msg - > from , msg - > len ) ;
msg - > retlen = msg - > len ;
mutex_unlock ( & qspi - > list_lock ) ;
return ret ;
}
2013-08-20 18:55:48 +05:30
static int ti_qspi_start_transfer_one ( struct spi_master * master ,
struct spi_message * m )
{
struct ti_qspi * qspi = spi_master_get_devdata ( master ) ;
struct spi_device * spi = m - > spi ;
struct spi_transfer * t ;
int status = 0 , ret ;
int frame_length ;
/* setup device control reg */
qspi - > dc = 0 ;
if ( spi - > mode & SPI_CPHA )
qspi - > dc | = QSPI_CKPHA ( spi - > chip_select ) ;
if ( spi - > mode & SPI_CPOL )
qspi - > dc | = QSPI_CKPOL ( spi - > chip_select ) ;
if ( spi - > mode & SPI_CS_HIGH )
qspi - > dc | = QSPI_CSPOL ( spi - > chip_select ) ;
frame_length = ( m - > frame_length < < 3 ) / spi - > bits_per_word ;
frame_length = clamp ( frame_length , 0 , QSPI_FRAME ) ;
/* setup command reg */
qspi - > cmd = 0 ;
qspi - > cmd | = QSPI_EN_CS ( spi - > chip_select ) ;
qspi - > cmd | = QSPI_FLEN ( frame_length ) ;
ti_qspi_write ( qspi , qspi - > dc , QSPI_SPI_DC_REG ) ;
mutex_lock ( & qspi - > list_lock ) ;
2015-12-11 09:39:57 +05:30
if ( qspi - > mmap_enabled )
ti_qspi_disable_memory_map ( spi ) ;
2013-08-20 18:55:48 +05:30
list_for_each_entry ( t , & m - > transfers , transfer_list ) {
qspi - > cmd | = QSPI_WLEN ( t - > bits_per_word ) ;
ret = qspi_transfer_msg ( qspi , t ) ;
if ( ret ) {
dev_dbg ( qspi - > dev , " transfer message failed \n " ) ;
2013-09-01 09:01:00 +08:00
mutex_unlock ( & qspi - > list_lock ) ;
2013-08-20 18:55:48 +05:30
return - EINVAL ;
}
m - > actual_length + = t - > len ;
}
mutex_unlock ( & qspi - > list_lock ) ;
2015-10-12 13:22:02 +05:30
ti_qspi_write ( qspi , qspi - > cmd | QSPI_INVAL , QSPI_SPI_CMD_REG ) ;
2013-08-20 18:55:48 +05:30
m - > status = status ;
spi_finalize_current_message ( master ) ;
return status ;
}
static int ti_qspi_runtime_resume ( struct device * dev )
{
struct ti_qspi * qspi ;
2013-12-20 18:22:57 +05:30
qspi = dev_get_drvdata ( dev ) ;
2013-08-20 18:55:48 +05:30
ti_qspi_restore_ctx ( qspi ) ;
return 0 ;
}
static const struct of_device_id ti_qspi_match [ ] = {
{ . compatible = " ti,dra7xxx-qspi " } ,
2013-08-27 19:42:24 +05:30
{ . compatible = " ti,am4372-qspi " } ,
2013-08-20 18:55:48 +05:30
{ } ,
} ;
2013-08-27 12:41:20 +05:30
MODULE_DEVICE_TABLE ( of , ti_qspi_match ) ;
2013-08-20 18:55:48 +05:30
static int ti_qspi_probe ( struct platform_device * pdev )
{
struct ti_qspi * qspi ;
struct spi_master * master ;
2015-12-11 09:39:57 +05:30
struct resource * r , * res_mmap ;
2013-08-20 18:55:48 +05:30
struct device_node * np = pdev - > dev . of_node ;
u32 max_freq ;
int ret = 0 , num_cs , irq ;
master = spi_alloc_master ( & pdev - > dev , sizeof ( * qspi ) ) ;
if ( ! master )
return - ENOMEM ;
2013-09-24 20:41:23 +05:30
master - > mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_RX_QUAD ;
2013-08-20 18:55:48 +05:30
master - > flags = SPI_MASTER_HALF_DUPLEX ;
master - > setup = ti_qspi_setup ;
master - > auto_runtime_pm = true ;
master - > transfer_one_message = ti_qspi_start_transfer_one ;
master - > dev . of_node = pdev - > dev . of_node ;
2014-02-05 21:59:18 +08:00
master - > bits_per_word_mask = SPI_BPW_MASK ( 32 ) | SPI_BPW_MASK ( 16 ) |
SPI_BPW_MASK ( 8 ) ;
2013-08-20 18:55:48 +05:30
if ( ! of_property_read_u32 ( np , " num-cs " , & num_cs ) )
master - > num_chipselect = num_cs ;
qspi = spi_master_get_devdata ( master ) ;
qspi - > master = master ;
qspi - > dev = & pdev - > dev ;
2013-11-11 14:13:41 +08:00
platform_set_drvdata ( pdev , qspi ) ;
2013-08-20 18:55:48 +05:30
2013-12-06 19:54:43 +05:30
r = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " qspi_base " ) ;
if ( r = = NULL ) {
r = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( r = = NULL ) {
dev_err ( & pdev - > dev , " missing platform data \n " ) ;
return - ENODEV ;
}
}
2013-08-20 18:55:48 +05:30
2013-12-06 19:54:43 +05:30
res_mmap = platform_get_resource_byname ( pdev ,
IORESOURCE_MEM , " qspi_mmap " ) ;
if ( res_mmap = = NULL ) {
res_mmap = platform_get_resource ( pdev , IORESOURCE_MEM , 1 ) ;
if ( res_mmap = = NULL ) {
dev_err ( & pdev - > dev ,
" memory mapped resource not required \n " ) ;
}
}
2013-08-20 18:55:48 +05:30
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
dev_err ( & pdev - > dev , " no irq resource? \n " ) ;
return irq ;
}
mutex_init ( & qspi - > list_lock ) ;
qspi - > base = devm_ioremap_resource ( & pdev - > dev , r ) ;
if ( IS_ERR ( qspi - > base ) ) {
ret = PTR_ERR ( qspi - > base ) ;
goto free_master ;
}
2013-12-06 19:54:43 +05:30
if ( res_mmap ) {
2015-12-11 09:39:57 +05:30
qspi - > mmap_base = devm_ioremap_resource ( & pdev - > dev ,
res_mmap ) ;
master - > spi_flash_read = ti_qspi_spi_flash_read ;
2013-12-06 19:54:43 +05:30
if ( IS_ERR ( qspi - > mmap_base ) ) {
2015-12-11 09:39:57 +05:30
dev_err ( & pdev - > dev ,
" falling back to PIO mode \n " ) ;
master - > spi_flash_read = NULL ;
}
}
qspi - > mmap_enabled = false ;
if ( of_property_read_bool ( np , " syscon-chipselects " ) ) {
qspi - > ctrl_base =
syscon_regmap_lookup_by_phandle ( np ,
" syscon-chipselects " ) ;
if ( IS_ERR ( qspi - > ctrl_base ) )
return PTR_ERR ( qspi - > ctrl_base ) ;
ret = of_property_read_u32_index ( np ,
" syscon-chipselects " ,
1 , & qspi - > ctrl_reg ) ;
if ( ret ) {
dev_err ( & pdev - > dev ,
" couldn't get ctrl_mod reg index \n " ) ;
return ret ;
2013-12-06 19:54:43 +05:30
}
}
2013-08-20 18:55:48 +05:30
qspi - > fclk = devm_clk_get ( & pdev - > dev , " fck " ) ;
if ( IS_ERR ( qspi - > fclk ) ) {
ret = PTR_ERR ( qspi - > fclk ) ;
dev_err ( & pdev - > dev , " could not get clk: %d \n " , ret ) ;
}
pm_runtime_use_autosuspend ( & pdev - > dev ) ;
pm_runtime_set_autosuspend_delay ( & pdev - > dev , QSPI_AUTOSUSPEND_TIMEOUT ) ;
pm_runtime_enable ( & pdev - > dev ) ;
if ( ! of_property_read_u32 ( np , " spi-max-frequency " , & max_freq ) )
qspi - > spi_max_frequency = max_freq ;
2013-09-24 13:52:37 +09:00
ret = devm_spi_register_master ( & pdev - > dev , master ) ;
2013-08-20 18:55:48 +05:30
if ( ret )
goto free_master ;
return 0 ;
free_master :
spi_master_put ( master ) ;
return ret ;
}
static int ti_qspi_remove ( struct platform_device * pdev )
{
2015-10-29 08:57:30 -05:00
pm_runtime_put_sync ( & pdev - > dev ) ;
2013-11-19 18:37:16 +05:30
pm_runtime_disable ( & pdev - > dev ) ;
2013-08-20 18:55:48 +05:30
return 0 ;
}
static const struct dev_pm_ops ti_qspi_pm_ops = {
. runtime_resume = ti_qspi_runtime_resume ,
} ;
static struct platform_driver ti_qspi_driver = {
. probe = ti_qspi_probe ,
2013-10-07 12:02:26 +01:00
. remove = ti_qspi_remove ,
2013-08-20 18:55:48 +05:30
. driver = {
2014-01-12 15:02:32 +08:00
. name = " ti-qspi " ,
2013-08-20 18:55:48 +05:30
. pm = & ti_qspi_pm_ops ,
. of_match_table = ti_qspi_match ,
}
} ;
module_platform_driver ( ti_qspi_driver ) ;
MODULE_AUTHOR ( " Sourav Poddar <sourav.poddar@ti.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_DESCRIPTION ( " TI QSPI controller driver " ) ;
2014-01-12 15:02:32 +08:00
MODULE_ALIAS ( " platform:ti-qspi " ) ;