2008-10-24 01:22:07 +04:00
/*
* TX4939 internal IDE driver
* Based on RBTX49xx patch from CELF patch archive .
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* ( C ) Copyright TOSHIBA CORPORATION 2005 - 2007
*/
# include <linux/module.h>
# include <linux/types.h>
# include <linux/ide.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/platform_device.h>
# include <linux/io.h>
# include <linux/scatterlist.h>
2009-03-27 14:46:26 +03:00
# include <asm/ide.h>
2008-10-24 01:22:07 +04:00
# define MODNAME "tx4939ide"
/* ATA Shadow Registers (8-bit except for Data which is 16-bit) */
# define TX4939IDE_Data 0x000
# define TX4939IDE_Error_Feature 0x001
# define TX4939IDE_Sec 0x002
# define TX4939IDE_LBA0 0x003
# define TX4939IDE_LBA1 0x004
# define TX4939IDE_LBA2 0x005
# define TX4939IDE_DevHead 0x006
# define TX4939IDE_Stat_Cmd 0x007
# define TX4939IDE_AltStat_DevCtl 0x402
/* H/W DMA Registers */
# define TX4939IDE_DMA_Cmd 0x800 /* 8-bit */
# define TX4939IDE_DMA_Stat 0x802 /* 8-bit */
# define TX4939IDE_PRD_Ptr 0x804 /* 32-bit */
/* ATA100 CORE Registers (16-bit) */
# define TX4939IDE_Sys_Ctl 0xc00
# define TX4939IDE_Xfer_Cnt_1 0xc08
# define TX4939IDE_Xfer_Cnt_2 0xc0a
# define TX4939IDE_Sec_Cnt 0xc10
# define TX4939IDE_Start_Lo_Addr 0xc18
# define TX4939IDE_Start_Up_Addr 0xc20
# define TX4939IDE_Add_Ctl 0xc28
# define TX4939IDE_Lo_Burst_Cnt 0xc30
# define TX4939IDE_Up_Burst_Cnt 0xc38
# define TX4939IDE_PIO_Addr 0xc88
# define TX4939IDE_H_Rst_Tim 0xc90
# define TX4939IDE_Int_Ctl 0xc98
# define TX4939IDE_Pkt_Cmd 0xcb8
# define TX4939IDE_Bxfer_Cnt_Hi 0xcc0
# define TX4939IDE_Bxfer_Cnt_Lo 0xcc8
# define TX4939IDE_Dev_TErr 0xcd0
# define TX4939IDE_Pkt_Xfer_Ctl 0xcd8
# define TX4939IDE_Start_TAddr 0xce0
/* bits for Int_Ctl */
# define TX4939IDE_INT_ADDRERR 0x80
# define TX4939IDE_INT_REACHMUL 0x40
# define TX4939IDE_INT_DEVTIMING 0x20
# define TX4939IDE_INT_UDMATERM 0x10
# define TX4939IDE_INT_TIMER 0x08
# define TX4939IDE_INT_BUSERR 0x04
# define TX4939IDE_INT_XFEREND 0x02
# define TX4939IDE_INT_HOST 0x01
# define TX4939IDE_IGNORE_INTS \
( TX4939IDE_INT_ADDRERR | TX4939IDE_INT_REACHMUL | \
TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_UDMATERM | \
TX4939IDE_INT_TIMER | TX4939IDE_INT_XFEREND )
# ifdef __BIG_ENDIAN
# define tx4939ide_swizzlel(a) ((a) ^ 4)
# define tx4939ide_swizzlew(a) ((a) ^ 6)
# define tx4939ide_swizzleb(a) ((a) ^ 7)
# else
# define tx4939ide_swizzlel(a) (a)
# define tx4939ide_swizzlew(a) (a)
# define tx4939ide_swizzleb(a) (a)
# endif
static u16 tx4939ide_readw ( void __iomem * base , u32 reg )
{
return __raw_readw ( base + tx4939ide_swizzlew ( reg ) ) ;
}
static u8 tx4939ide_readb ( void __iomem * base , u32 reg )
{
return __raw_readb ( base + tx4939ide_swizzleb ( reg ) ) ;
}
static void tx4939ide_writel ( u32 val , void __iomem * base , u32 reg )
{
__raw_writel ( val , base + tx4939ide_swizzlel ( reg ) ) ;
}
static void tx4939ide_writew ( u16 val , void __iomem * base , u32 reg )
{
__raw_writew ( val , base + tx4939ide_swizzlew ( reg ) ) ;
}
static void tx4939ide_writeb ( u8 val , void __iomem * base , u32 reg )
{
__raw_writeb ( val , base + tx4939ide_swizzleb ( reg ) ) ;
}
# define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base)
2010-01-19 12:44:41 +03:00
static void tx4939ide_set_pio_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2008-10-24 01:22:07 +04:00
{
int is_slave = drive - > dn ;
u32 mask , val ;
2010-01-19 12:44:41 +03:00
const u8 pio = drive - > pio_mode - XFER_PIO_0 ;
2008-10-24 01:22:07 +04:00
u8 safe = pio ;
ide_drive_t * pair ;
pair = ide_get_pair_dev ( drive ) ;
if ( pair )
2010-06-05 03:19:23 +04:00
safe = min_t ( u8 , safe , pair - > pio_mode - XFER_PIO_0 ) ;
2008-10-24 01:22:07 +04:00
/*
* Update Command Transfer Mode for master / slave and Data
* Transfer Mode for this drive .
*/
mask = is_slave ? 0x07f00000 : 0x000007f0 ;
val = ( ( safe < < 8 ) | ( pio < < 4 ) ) < < ( is_slave ? 16 : 0 ) ;
hwif - > select_data = ( hwif - > select_data & ~ mask ) | val ;
/* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
}
2010-01-19 12:45:29 +03:00
static void tx4939ide_set_dma_mode ( ide_hwif_t * hwif , ide_drive_t * drive )
2008-10-24 01:22:07 +04:00
{
u32 mask , val ;
2010-01-19 12:45:29 +03:00
const u8 mode = drive - > dma_mode ;
2008-10-24 01:22:07 +04:00
/* Update Data Transfer Mode for this drive. */
if ( mode > = XFER_UDMA_0 )
val = mode - XFER_UDMA_0 + 8 ;
else
val = mode - XFER_MW_DMA_0 + 5 ;
if ( drive - > dn ) {
mask = 0x00f00000 ;
val < < = 20 ;
} else {
mask = 0x000000f0 ;
val < < = 4 ;
}
hwif - > select_data = ( hwif - > select_data & ~ mask ) | val ;
/* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */
}
static u16 tx4939ide_check_error_ints ( ide_hwif_t * hwif )
{
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
u16 ctl = tx4939ide_readw ( base , TX4939IDE_Int_Ctl ) ;
if ( ctl & TX4939IDE_INT_BUSERR ) {
/* reset FIFO */
u16 sysctl = tx4939ide_readw ( base , TX4939IDE_Sys_Ctl ) ;
tx4939ide_writew ( sysctl | 0x4000 , base , TX4939IDE_Sys_Ctl ) ;
mmiowb ( ) ;
/* wait 12GBUSCLK (typ. 60ns @ GBUS200MHz, max 270ns) */
ndelay ( 270 ) ;
tx4939ide_writew ( sysctl , base , TX4939IDE_Sys_Ctl ) ;
}
if ( ctl & ( TX4939IDE_INT_ADDRERR |
TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_BUSERR ) )
pr_err ( " %s: Error interrupt %#x (%s%s%s ) \n " ,
hwif - > name , ctl ,
ctl & TX4939IDE_INT_ADDRERR ? " Address-Error " : " " ,
ctl & TX4939IDE_INT_DEVTIMING ? " DEV-Timing " : " " ,
ctl & TX4939IDE_INT_BUSERR ? " Bus-Error " : " " ) ;
return ctl ;
}
static void tx4939ide_clear_irq ( ide_drive_t * drive )
{
ide_hwif_t * hwif ;
void __iomem * base ;
u16 ctl ;
/*
* tx4939ide_dma_test_irq ( ) and tx4939ide_dma_end ( ) do all job
* for DMA case .
*/
if ( drive - > waiting_for_dma )
return ;
hwif = drive - > hwif ;
base = TX4939IDE_BASE ( hwif ) ;
ctl = tx4939ide_check_error_ints ( hwif ) ;
tx4939ide_writew ( ctl , base , TX4939IDE_Int_Ctl ) ;
}
static u8 tx4939ide_cable_detect ( ide_hwif_t * hwif )
{
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
return tx4939ide_readw ( base , TX4939IDE_Sys_Ctl ) & 0x2000 ?
ATA_CBL_PATA40 : ATA_CBL_PATA80 ;
}
# ifdef __BIG_ENDIAN
static void tx4939ide_dma_host_set ( ide_drive_t * drive , int on )
{
ide_hwif_t * hwif = drive - > hwif ;
u8 unit = drive - > dn ;
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
u8 dma_stat = tx4939ide_readb ( base , TX4939IDE_DMA_Stat ) ;
if ( on )
dma_stat | = ( 1 < < ( 5 + unit ) ) ;
else
dma_stat & = ~ ( 1 < < ( 5 + unit ) ) ;
tx4939ide_writeb ( dma_stat , base , TX4939IDE_DMA_Stat ) ;
}
# else
# define tx4939ide_dma_host_set ide_dma_host_set
# endif
static u8 tx4939ide_clear_dma_status ( void __iomem * base )
{
u8 dma_stat ;
/* read DMA status for INTR & ERROR flags */
dma_stat = tx4939ide_readb ( base , TX4939IDE_DMA_Stat ) ;
/* clear INTR & ERROR flags */
tx4939ide_writeb ( dma_stat | ATA_DMA_INTR | ATA_DMA_ERR , base ,
TX4939IDE_DMA_Stat ) ;
/* recover intmask cleared by writing to bit2 of DMA_Stat */
tx4939ide_writew ( TX4939IDE_IGNORE_INTS < < 8 , base , TX4939IDE_Int_Ctl ) ;
return dma_stat ;
}
# ifdef __BIG_ENDIAN
/* custom ide_build_dmatable to handle swapped layout */
2009-03-27 14:46:46 +03:00
static int tx4939ide_build_dmatable ( ide_drive_t * drive , struct ide_cmd * cmd )
2008-10-24 01:22:07 +04:00
{
ide_hwif_t * hwif = drive - > hwif ;
u32 * table = ( u32 * ) hwif - > dmatable_cpu ;
unsigned int count = 0 ;
int i ;
struct scatterlist * sg ;
2009-03-27 14:46:46 +03:00
for_each_sg ( hwif - > sg_table , sg , cmd - > sg_nents , i ) {
2008-10-24 01:22:07 +04:00
u32 cur_addr , cur_len , bcount ;
cur_addr = sg_dma_address ( sg ) ;
cur_len = sg_dma_len ( sg ) ;
/*
* Fill in the DMA table , without crossing any 64 kB boundaries .
*/
while ( cur_len ) {
if ( count + + > = PRD_ENTRIES )
goto use_pio_instead ;
bcount = 0x10000 - ( cur_addr & 0xffff ) ;
if ( bcount > cur_len )
bcount = cur_len ;
2008-12-29 22:27:28 +03:00
/*
* This workaround for zero count seems required .
2009-02-02 22:12:23 +03:00
* ( standard ide_build_dmatable does it too )
2008-12-29 22:27:28 +03:00
*/
2009-02-02 22:12:23 +03:00
if ( bcount = = 0x10000 )
2008-12-29 22:27:28 +03:00
bcount = 0x8000 ;
2008-10-24 01:22:07 +04:00
* table + + = bcount & 0xffff ;
* table + + = cur_addr ;
cur_addr + = bcount ;
cur_len - = bcount ;
}
}
if ( count ) {
* ( table - 2 ) | = 0x80000000 ;
return count ;
}
use_pio_instead :
printk ( KERN_ERR " %s: %s \n " , drive - > name ,
count ? " DMA table too small " : " empty DMA table? " ) ;
return 0 ; /* revert to PIO for this request */
}
# else
# define tx4939ide_build_dmatable ide_build_dmatable
# endif
2009-03-27 14:46:46 +03:00
static int tx4939ide_dma_setup ( ide_drive_t * drive , struct ide_cmd * cmd )
2008-10-24 01:22:07 +04:00
{
ide_hwif_t * hwif = drive - > hwif ;
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
2009-03-27 14:46:46 +03:00
u8 rw = ( cmd - > tf_flags & IDE_TFLAG_WRITE ) ? 0 : ATA_DMA_WR ;
2008-10-24 01:22:07 +04:00
/* fall back to PIO! */
2009-03-31 22:15:21 +04:00
if ( tx4939ide_build_dmatable ( drive , cmd ) = = 0 )
2008-10-24 01:22:07 +04:00
return 1 ;
/* PRD table */
tx4939ide_writel ( hwif - > dmatable_dma , base , TX4939IDE_PRD_Ptr ) ;
/* specify r/w */
2009-03-27 14:46:46 +03:00
tx4939ide_writeb ( rw , base , TX4939IDE_DMA_Cmd ) ;
2008-10-24 01:22:07 +04:00
/* clear INTR & ERROR flags */
tx4939ide_clear_dma_status ( base ) ;
tx4939ide_writew ( SECTOR_SIZE / 2 , base , drive - > dn ?
TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1 ) ;
2009-03-27 14:46:46 +03:00
2009-05-07 17:24:40 +04:00
tx4939ide_writew ( blk_rq_sectors ( cmd - > rq ) , base , TX4939IDE_Sec_Cnt ) ;
2009-03-27 14:46:46 +03:00
2008-10-24 01:22:07 +04:00
return 0 ;
}
static int tx4939ide_dma_end ( ide_drive_t * drive )
{
ide_hwif_t * hwif = drive - > hwif ;
u8 dma_stat , dma_cmd ;
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
u16 ctl = tx4939ide_readw ( base , TX4939IDE_Int_Ctl ) ;
/* get DMA command mode */
dma_cmd = tx4939ide_readb ( base , TX4939IDE_DMA_Cmd ) ;
/* stop DMA */
tx4939ide_writeb ( dma_cmd & ~ ATA_DMA_START , base , TX4939IDE_DMA_Cmd ) ;
/* read and clear the INTR & ERROR bits */
dma_stat = tx4939ide_clear_dma_status ( base ) ;
2009-04-08 16:12:49 +04:00
# define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR)
2008-10-24 01:22:07 +04:00
2009-03-31 22:15:20 +04:00
/* verify good DMA status */
2009-04-08 16:12:49 +04:00
if ( ( dma_stat & CHECK_DMA_MASK ) = = 0 & &
2008-10-24 01:22:07 +04:00
( ctl & ( TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST ) ) = =
( TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST ) )
/* INT_IDE lost... bug? */
return 0 ;
2009-04-08 16:12:49 +04:00
return ( ( dma_stat & CHECK_DMA_MASK ) ! =
2008-10-24 01:22:07 +04:00
ATA_DMA_INTR ) ? 0x10 | dma_stat : 0 ;
}
/* returns 1 if DMA IRQ issued, 0 otherwise */
static int tx4939ide_dma_test_irq ( ide_drive_t * drive )
{
ide_hwif_t * hwif = drive - > hwif ;
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
u16 ctl , ide_int ;
u8 dma_stat , stat ;
int found = 0 ;
ctl = tx4939ide_check_error_ints ( hwif ) ;
ide_int = ctl & ( TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST ) ;
switch ( ide_int ) {
case TX4939IDE_INT_HOST :
/* On error, XFEREND might not be asserted. */
stat = tx4939ide_readb ( base , TX4939IDE_AltStat_DevCtl ) ;
if ( ( stat & ( ATA_BUSY | ATA_DRQ | ATA_ERR ) ) = = ATA_ERR )
found = 1 ;
else
/* Wait for XFEREND (Mask HOST and unmask XFEREND) */
ctl & = ~ TX4939IDE_INT_XFEREND < < 8 ;
ctl | = ide_int < < 8 ;
break ;
case TX4939IDE_INT_HOST | TX4939IDE_INT_XFEREND :
dma_stat = tx4939ide_readb ( base , TX4939IDE_DMA_Stat ) ;
if ( ! ( dma_stat & ATA_DMA_INTR ) )
pr_warning ( " %s: weird interrupt status. "
" DMA_Stat %#02x int_ctl %#04x \n " ,
hwif - > name , dma_stat , ctl ) ;
found = 1 ;
break ;
}
/*
* Do not clear XFEREND , HOST now . They will be cleared by
* clearing bit2 of DMA_Stat .
*/
ctl & = ~ ide_int ;
tx4939ide_writew ( ctl , base , TX4939IDE_Int_Ctl ) ;
return found ;
}
2009-01-06 19:21:02 +03:00
# ifdef __BIG_ENDIAN
static u8 tx4939ide_dma_sff_read_status ( ide_hwif_t * hwif )
{
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
return tx4939ide_readb ( base , TX4939IDE_DMA_Stat ) ;
}
# else
# define tx4939ide_dma_sff_read_status ide_dma_sff_read_status
# endif
2008-10-24 01:22:07 +04:00
static void tx4939ide_init_hwif ( ide_hwif_t * hwif )
{
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
/* Soft Reset */
tx4939ide_writew ( 0x8000 , base , TX4939IDE_Sys_Ctl ) ;
mmiowb ( ) ;
/* at least 20 GBUSCLK (typ. 100ns @ GBUS200MHz, max 450ns) */
ndelay ( 450 ) ;
tx4939ide_writew ( 0x0000 , base , TX4939IDE_Sys_Ctl ) ;
/* mask some interrupts and clear all interrupts */
tx4939ide_writew ( ( TX4939IDE_IGNORE_INTS < < 8 ) | 0xff , base ,
TX4939IDE_Int_Ctl ) ;
tx4939ide_writew ( 0x0008 , base , TX4939IDE_Lo_Burst_Cnt ) ;
tx4939ide_writew ( 0 , base , TX4939IDE_Up_Burst_Cnt ) ;
}
static int tx4939ide_init_dma ( ide_hwif_t * hwif , const struct ide_port_info * d )
{
hwif - > dma_base =
hwif - > extra_base + tx4939ide_swizzleb ( TX4939IDE_DMA_Cmd ) ;
/*
* Note that we cannot use ATA_DMA_TABLE_OFS , ATA_DMA_STATUS
* for big endian .
*/
return ide_allocate_dma_engine ( hwif ) ;
}
2009-03-27 14:46:37 +03:00
static void tx4939ide_tf_load_fixup ( ide_drive_t * drive )
2008-10-24 01:22:07 +04:00
{
ide_hwif_t * hwif = drive - > hwif ;
void __iomem * base = TX4939IDE_BASE ( hwif ) ;
u16 sysctl = hwif - > select_data > > ( drive - > dn ? 16 : 0 ) ;
/*
* Fix ATA100 CORE System Control Register . ( The write to the
* Device / Head register may write wrong data to the System
* Control Register )
2009-03-31 22:15:32 +04:00
* While Sys_Ctl is written here , dev_select ( ) is not needed .
2008-10-24 01:22:07 +04:00
*/
tx4939ide_writew ( sysctl , base , TX4939IDE_Sys_Ctl ) ;
}
2009-04-08 16:13:03 +04:00
static void tx4939ide_tf_load ( ide_drive_t * drive , struct ide_taskfile * tf ,
u8 valid )
2008-10-24 01:22:07 +04:00
{
2009-04-08 16:13:03 +04:00
ide_tf_load ( drive , tf , valid ) ;
2009-04-08 16:12:52 +04:00
2009-04-08 16:13:03 +04:00
if ( valid & IDE_VALID_DEVICE )
2009-03-27 14:46:37 +03:00
tx4939ide_tf_load_fixup ( drive ) ;
2008-10-24 01:22:07 +04:00
}
2009-04-08 16:12:52 +04:00
# ifdef __BIG_ENDIAN
2008-10-24 01:22:07 +04:00
2009-04-08 16:12:52 +04:00
/* custom iops (independent from SWAP_IO_SPACE) */
2009-04-08 16:12:52 +04:00
static void tx4939ide_input_data_swap ( ide_drive_t * drive , struct ide_cmd * cmd ,
2008-10-24 01:22:07 +04:00
void * buf , unsigned int len )
{
unsigned long port = drive - > hwif - > io_ports . data_addr ;
unsigned short * ptr = buf ;
unsigned int count = ( len + 1 ) / 2 ;
while ( count - - )
* ptr + + = cpu_to_le16 ( __raw_readw ( ( void __iomem * ) port ) ) ;
2008-12-29 22:27:29 +03:00
__ide_flush_dcache_range ( ( unsigned long ) buf , roundup ( len , 2 ) ) ;
2008-10-24 01:22:07 +04:00
}
2009-04-08 16:12:52 +04:00
static void tx4939ide_output_data_swap ( ide_drive_t * drive , struct ide_cmd * cmd ,
2008-10-24 01:22:07 +04:00
void * buf , unsigned int len )
{
unsigned long port = drive - > hwif - > io_ports . data_addr ;
unsigned short * ptr = buf ;
unsigned int count = ( len + 1 ) / 2 ;
while ( count - - ) {
__raw_writew ( le16_to_cpu ( * ptr ) , ( void __iomem * ) port ) ;
ptr + + ;
}
2008-12-29 22:27:29 +03:00
__ide_flush_dcache_range ( ( unsigned long ) buf , roundup ( len , 2 ) ) ;
2008-10-24 01:22:07 +04:00
}
static const struct ide_tp_ops tx4939ide_tp_ops = {
. exec_command = ide_exec_command ,
. read_status = ide_read_status ,
. read_altstatus = ide_read_altstatus ,
2009-03-31 22:15:30 +04:00
. write_devctl = ide_write_devctl ,
2008-10-24 01:22:07 +04:00
2009-03-31 22:15:32 +04:00
. dev_select = ide_dev_select ,
2008-10-24 01:22:07 +04:00
. tf_load = tx4939ide_tf_load ,
2009-04-08 16:12:52 +04:00
. tf_read = ide_tf_read ,
2008-10-24 01:22:07 +04:00
. input_data = tx4939ide_input_data_swap ,
. output_data = tx4939ide_output_data_swap ,
} ;
# else /* __LITTLE_ENDIAN */
static const struct ide_tp_ops tx4939ide_tp_ops = {
. exec_command = ide_exec_command ,
. read_status = ide_read_status ,
. read_altstatus = ide_read_altstatus ,
2009-03-31 22:15:30 +04:00
. write_devctl = ide_write_devctl ,
2008-10-24 01:22:07 +04:00
2009-03-31 22:15:32 +04:00
. dev_select = ide_dev_select ,
2008-10-24 01:22:07 +04:00
. tf_load = tx4939ide_tf_load ,
. tf_read = ide_tf_read ,
. input_data = ide_input_data ,
. output_data = ide_output_data ,
} ;
# endif /* __LITTLE_ENDIAN */
static const struct ide_port_ops tx4939ide_port_ops = {
2009-01-02 18:12:46 +03:00
. set_pio_mode = tx4939ide_set_pio_mode ,
. set_dma_mode = tx4939ide_set_dma_mode ,
. clear_irq = tx4939ide_clear_irq ,
. cable_detect = tx4939ide_cable_detect ,
2008-10-24 01:22:07 +04:00
} ;
static const struct ide_dma_ops tx4939ide_dma_ops = {
2009-01-02 18:12:46 +03:00
. dma_host_set = tx4939ide_dma_host_set ,
. dma_setup = tx4939ide_dma_setup ,
. dma_start = ide_dma_start ,
. dma_end = tx4939ide_dma_end ,
. dma_test_irq = tx4939ide_dma_test_irq ,
. dma_lost_irq = ide_dma_lost_irq ,
2009-03-27 14:46:47 +03:00
. dma_timer_expiry = ide_dma_sff_timer_expiry ,
2009-01-06 19:21:02 +03:00
. dma_sff_read_status = tx4939ide_dma_sff_read_status ,
2008-10-24 01:22:07 +04:00
} ;
2012-10-05 04:11:48 +04:00
static const struct ide_port_info tx4939ide_port_info __initconst = {
2009-01-02 18:12:46 +03:00
. init_hwif = tx4939ide_init_hwif ,
. init_dma = tx4939ide_init_dma ,
. port_ops = & tx4939ide_port_ops ,
. dma_ops = & tx4939ide_dma_ops ,
. tp_ops = & tx4939ide_tp_ops ,
. host_flags = IDE_HFLAG_MMIO ,
. pio_mask = ATA_PIO4 ,
. mwdma_mask = ATA_MWDMA2 ,
. udma_mask = ATA_UDMA5 ,
2009-01-02 18:12:47 +03:00
. chipset = ide_generic ,
2008-10-24 01:22:07 +04:00
} ;
static int __init tx4939ide_probe ( struct platform_device * pdev )
{
2009-05-17 21:12:25 +04:00
struct ide_hw hw , * hws [ ] = { & hw } ;
2008-10-24 01:22:07 +04:00
struct ide_host * host ;
struct resource * res ;
int irq , ret ;
unsigned long mapbase ;
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 )
return - ENODEV ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - ENODEV ;
if ( ! devm_request_mem_region ( & pdev - > dev , res - > start ,
2011-06-09 20:13:32 +04:00
resource_size ( res ) , " tx4938ide " ) )
2008-10-24 01:22:07 +04:00
return - EBUSY ;
mapbase = ( unsigned long ) devm_ioremap ( & pdev - > dev , res - > start ,
2011-06-09 20:13:32 +04:00
resource_size ( res ) ) ;
2008-10-24 01:22:07 +04:00
if ( ! mapbase )
return - EBUSY ;
memset ( & hw , 0 , sizeof ( hw ) ) ;
hw . io_ports . data_addr =
mapbase + tx4939ide_swizzlew ( TX4939IDE_Data ) ;
hw . io_ports . error_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_Error_Feature ) ;
hw . io_ports . nsect_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_Sec ) ;
hw . io_ports . lbal_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_LBA0 ) ;
hw . io_ports . lbam_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_LBA1 ) ;
hw . io_ports . lbah_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_LBA2 ) ;
hw . io_ports . device_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_DevHead ) ;
hw . io_ports . command_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_Stat_Cmd ) ;
hw . io_ports . ctl_addr =
mapbase + tx4939ide_swizzleb ( TX4939IDE_AltStat_DevCtl ) ;
hw . irq = irq ;
hw . dev = & pdev - > dev ;
pr_info ( " TX4939 IDE interface (base %#lx, irq %d) \n " , mapbase , irq ) ;
2009-05-17 21:12:24 +04:00
host = ide_host_alloc ( & tx4939ide_port_info , hws , 1 ) ;
2008-10-24 01:22:07 +04:00
if ( ! host )
return - ENOMEM ;
/* use extra_base for base address of the all registers */
host - > ports [ 0 ] - > extra_base = mapbase ;
ret = ide_host_register ( host , & tx4939ide_port_info , hws ) ;
if ( ret ) {
ide_host_free ( host ) ;
return ret ;
}
platform_set_drvdata ( pdev , host ) ;
return 0 ;
}
static int __exit tx4939ide_remove ( struct platform_device * pdev )
{
struct ide_host * host = platform_get_drvdata ( pdev ) ;
ide_host_remove ( host ) ;
return 0 ;
}
# ifdef CONFIG_PM
static int tx4939ide_resume ( struct platform_device * dev )
{
struct ide_host * host = platform_get_drvdata ( dev ) ;
ide_hwif_t * hwif = host - > ports [ 0 ] ;
tx4939ide_init_hwif ( hwif ) ;
return 0 ;
}
# else
# define tx4939ide_resume NULL
# endif
static struct platform_driver tx4939ide_driver = {
. driver = {
. name = MODNAME ,
} ,
. remove = __exit_p ( tx4939ide_remove ) ,
. resume = tx4939ide_resume ,
} ;
2013-03-04 20:26:53 +04:00
module_platform_driver_probe ( tx4939ide_driver , tx4939ide_probe ) ;
2008-10-24 01:22:07 +04:00
MODULE_DESCRIPTION ( " TX4939 internal IDE driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:tx4939ide " ) ;