18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * TX4939 internal IDE driver 38c2ecf20Sopenharmony_ci * Based on RBTX49xx patch from CELF patch archive. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 68c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 78c2ecf20Sopenharmony_ci * for more details. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * (C) Copyright TOSHIBA CORPORATION 2005-2007 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/ide.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <asm/ide.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define MODNAME "tx4939ide" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* ATA Shadow Registers (8-bit except for Data which is 16-bit) */ 268c2ecf20Sopenharmony_ci#define TX4939IDE_Data 0x000 278c2ecf20Sopenharmony_ci#define TX4939IDE_Error_Feature 0x001 288c2ecf20Sopenharmony_ci#define TX4939IDE_Sec 0x002 298c2ecf20Sopenharmony_ci#define TX4939IDE_LBA0 0x003 308c2ecf20Sopenharmony_ci#define TX4939IDE_LBA1 0x004 318c2ecf20Sopenharmony_ci#define TX4939IDE_LBA2 0x005 328c2ecf20Sopenharmony_ci#define TX4939IDE_DevHead 0x006 338c2ecf20Sopenharmony_ci#define TX4939IDE_Stat_Cmd 0x007 348c2ecf20Sopenharmony_ci#define TX4939IDE_AltStat_DevCtl 0x402 358c2ecf20Sopenharmony_ci/* H/W DMA Registers */ 368c2ecf20Sopenharmony_ci#define TX4939IDE_DMA_Cmd 0x800 /* 8-bit */ 378c2ecf20Sopenharmony_ci#define TX4939IDE_DMA_Stat 0x802 /* 8-bit */ 388c2ecf20Sopenharmony_ci#define TX4939IDE_PRD_Ptr 0x804 /* 32-bit */ 398c2ecf20Sopenharmony_ci/* ATA100 CORE Registers (16-bit) */ 408c2ecf20Sopenharmony_ci#define TX4939IDE_Sys_Ctl 0xc00 418c2ecf20Sopenharmony_ci#define TX4939IDE_Xfer_Cnt_1 0xc08 428c2ecf20Sopenharmony_ci#define TX4939IDE_Xfer_Cnt_2 0xc0a 438c2ecf20Sopenharmony_ci#define TX4939IDE_Sec_Cnt 0xc10 448c2ecf20Sopenharmony_ci#define TX4939IDE_Start_Lo_Addr 0xc18 458c2ecf20Sopenharmony_ci#define TX4939IDE_Start_Up_Addr 0xc20 468c2ecf20Sopenharmony_ci#define TX4939IDE_Add_Ctl 0xc28 478c2ecf20Sopenharmony_ci#define TX4939IDE_Lo_Burst_Cnt 0xc30 488c2ecf20Sopenharmony_ci#define TX4939IDE_Up_Burst_Cnt 0xc38 498c2ecf20Sopenharmony_ci#define TX4939IDE_PIO_Addr 0xc88 508c2ecf20Sopenharmony_ci#define TX4939IDE_H_Rst_Tim 0xc90 518c2ecf20Sopenharmony_ci#define TX4939IDE_Int_Ctl 0xc98 528c2ecf20Sopenharmony_ci#define TX4939IDE_Pkt_Cmd 0xcb8 538c2ecf20Sopenharmony_ci#define TX4939IDE_Bxfer_Cnt_Hi 0xcc0 548c2ecf20Sopenharmony_ci#define TX4939IDE_Bxfer_Cnt_Lo 0xcc8 558c2ecf20Sopenharmony_ci#define TX4939IDE_Dev_TErr 0xcd0 568c2ecf20Sopenharmony_ci#define TX4939IDE_Pkt_Xfer_Ctl 0xcd8 578c2ecf20Sopenharmony_ci#define TX4939IDE_Start_TAddr 0xce0 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* bits for Int_Ctl */ 608c2ecf20Sopenharmony_ci#define TX4939IDE_INT_ADDRERR 0x80 618c2ecf20Sopenharmony_ci#define TX4939IDE_INT_REACHMUL 0x40 628c2ecf20Sopenharmony_ci#define TX4939IDE_INT_DEVTIMING 0x20 638c2ecf20Sopenharmony_ci#define TX4939IDE_INT_UDMATERM 0x10 648c2ecf20Sopenharmony_ci#define TX4939IDE_INT_TIMER 0x08 658c2ecf20Sopenharmony_ci#define TX4939IDE_INT_BUSERR 0x04 668c2ecf20Sopenharmony_ci#define TX4939IDE_INT_XFEREND 0x02 678c2ecf20Sopenharmony_ci#define TX4939IDE_INT_HOST 0x01 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define TX4939IDE_IGNORE_INTS \ 708c2ecf20Sopenharmony_ci (TX4939IDE_INT_ADDRERR | TX4939IDE_INT_REACHMUL | \ 718c2ecf20Sopenharmony_ci TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_UDMATERM | \ 728c2ecf20Sopenharmony_ci TX4939IDE_INT_TIMER | TX4939IDE_INT_XFEREND) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 758c2ecf20Sopenharmony_ci#define tx4939ide_swizzlel(a) ((a) ^ 4) 768c2ecf20Sopenharmony_ci#define tx4939ide_swizzlew(a) ((a) ^ 6) 778c2ecf20Sopenharmony_ci#define tx4939ide_swizzleb(a) ((a) ^ 7) 788c2ecf20Sopenharmony_ci#else 798c2ecf20Sopenharmony_ci#define tx4939ide_swizzlel(a) (a) 808c2ecf20Sopenharmony_ci#define tx4939ide_swizzlew(a) (a) 818c2ecf20Sopenharmony_ci#define tx4939ide_swizzleb(a) (a) 828c2ecf20Sopenharmony_ci#endif 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic u16 tx4939ide_readw(void __iomem *base, u32 reg) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci return __raw_readw(base + tx4939ide_swizzlew(reg)); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_cistatic u8 tx4939ide_readb(void __iomem *base, u32 reg) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci return __raw_readb(base + tx4939ide_swizzleb(reg)); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_cistatic void tx4939ide_writel(u32 val, void __iomem *base, u32 reg) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci __raw_writel(val, base + tx4939ide_swizzlel(reg)); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_cistatic void tx4939ide_writew(u16 val, void __iomem *base, u32 reg) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci __raw_writew(val, base + tx4939ide_swizzlew(reg)); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_cistatic void tx4939ide_writeb(u8 val, void __iomem *base, u32 reg) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci __raw_writeb(val, base + tx4939ide_swizzleb(reg)); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define TX4939IDE_BASE(hwif) ((void __iomem *)(hwif)->extra_base) 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void tx4939ide_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int is_slave = drive->dn; 1108c2ecf20Sopenharmony_ci u32 mask, val; 1118c2ecf20Sopenharmony_ci const u8 pio = drive->pio_mode - XFER_PIO_0; 1128c2ecf20Sopenharmony_ci u8 safe = pio; 1138c2ecf20Sopenharmony_ci ide_drive_t *pair; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci pair = ide_get_pair_dev(drive); 1168c2ecf20Sopenharmony_ci if (pair) 1178c2ecf20Sopenharmony_ci safe = min_t(u8, safe, pair->pio_mode - XFER_PIO_0); 1188c2ecf20Sopenharmony_ci /* 1198c2ecf20Sopenharmony_ci * Update Command Transfer Mode for master/slave and Data 1208c2ecf20Sopenharmony_ci * Transfer Mode for this drive. 1218c2ecf20Sopenharmony_ci */ 1228c2ecf20Sopenharmony_ci mask = is_slave ? 0x07f00000 : 0x000007f0; 1238c2ecf20Sopenharmony_ci val = ((safe << 8) | (pio << 4)) << (is_slave ? 16 : 0); 1248c2ecf20Sopenharmony_ci hwif->select_data = (hwif->select_data & ~mask) | val; 1258c2ecf20Sopenharmony_ci /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */ 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic void tx4939ide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci u32 mask, val; 1318c2ecf20Sopenharmony_ci const u8 mode = drive->dma_mode; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Update Data Transfer Mode for this drive. */ 1348c2ecf20Sopenharmony_ci if (mode >= XFER_UDMA_0) 1358c2ecf20Sopenharmony_ci val = mode - XFER_UDMA_0 + 8; 1368c2ecf20Sopenharmony_ci else 1378c2ecf20Sopenharmony_ci val = mode - XFER_MW_DMA_0 + 5; 1388c2ecf20Sopenharmony_ci if (drive->dn) { 1398c2ecf20Sopenharmony_ci mask = 0x00f00000; 1408c2ecf20Sopenharmony_ci val <<= 20; 1418c2ecf20Sopenharmony_ci } else { 1428c2ecf20Sopenharmony_ci mask = 0x000000f0; 1438c2ecf20Sopenharmony_ci val <<= 4; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci hwif->select_data = (hwif->select_data & ~mask) | val; 1468c2ecf20Sopenharmony_ci /* tx4939ide_tf_load_fixup() will set the Sys_Ctl register */ 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic u16 tx4939ide_check_error_ints(ide_hwif_t *hwif) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 1528c2ecf20Sopenharmony_ci u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (ctl & TX4939IDE_INT_BUSERR) { 1558c2ecf20Sopenharmony_ci /* reset FIFO */ 1568c2ecf20Sopenharmony_ci u16 sysctl = tx4939ide_readw(base, TX4939IDE_Sys_Ctl); 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci tx4939ide_writew(sysctl | 0x4000, base, TX4939IDE_Sys_Ctl); 1598c2ecf20Sopenharmony_ci /* wait 12GBUSCLK (typ. 60ns @ GBUS200MHz, max 270ns) */ 1608c2ecf20Sopenharmony_ci ndelay(270); 1618c2ecf20Sopenharmony_ci tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci if (ctl & (TX4939IDE_INT_ADDRERR | 1648c2ecf20Sopenharmony_ci TX4939IDE_INT_DEVTIMING | TX4939IDE_INT_BUSERR)) 1658c2ecf20Sopenharmony_ci pr_err("%s: Error interrupt %#x (%s%s%s )\n", 1668c2ecf20Sopenharmony_ci hwif->name, ctl, 1678c2ecf20Sopenharmony_ci ctl & TX4939IDE_INT_ADDRERR ? " Address-Error" : "", 1688c2ecf20Sopenharmony_ci ctl & TX4939IDE_INT_DEVTIMING ? " DEV-Timing" : "", 1698c2ecf20Sopenharmony_ci ctl & TX4939IDE_INT_BUSERR ? " Bus-Error" : ""); 1708c2ecf20Sopenharmony_ci return ctl; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic void tx4939ide_clear_irq(ide_drive_t *drive) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci ide_hwif_t *hwif; 1768c2ecf20Sopenharmony_ci void __iomem *base; 1778c2ecf20Sopenharmony_ci u16 ctl; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci /* 1808c2ecf20Sopenharmony_ci * tx4939ide_dma_test_irq() and tx4939ide_dma_end() do all job 1818c2ecf20Sopenharmony_ci * for DMA case. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci if (drive->waiting_for_dma) 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci hwif = drive->hwif; 1868c2ecf20Sopenharmony_ci base = TX4939IDE_BASE(hwif); 1878c2ecf20Sopenharmony_ci ctl = tx4939ide_check_error_ints(hwif); 1888c2ecf20Sopenharmony_ci tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic u8 tx4939ide_cable_detect(ide_hwif_t *hwif) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci return tx4939ide_readw(base, TX4939IDE_Sys_Ctl) & 0x2000 ? 1968c2ecf20Sopenharmony_ci ATA_CBL_PATA40 : ATA_CBL_PATA80; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 2008c2ecf20Sopenharmony_cistatic void tx4939ide_dma_host_set(ide_drive_t *drive, int on) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 2038c2ecf20Sopenharmony_ci u8 unit = drive->dn; 2048c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 2058c2ecf20Sopenharmony_ci u8 dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (on) 2088c2ecf20Sopenharmony_ci dma_stat |= (1 << (5 + unit)); 2098c2ecf20Sopenharmony_ci else 2108c2ecf20Sopenharmony_ci dma_stat &= ~(1 << (5 + unit)); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci tx4939ide_writeb(dma_stat, base, TX4939IDE_DMA_Stat); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci#else 2158c2ecf20Sopenharmony_ci#define tx4939ide_dma_host_set ide_dma_host_set 2168c2ecf20Sopenharmony_ci#endif 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic u8 tx4939ide_clear_dma_status(void __iomem *base) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci u8 dma_stat; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* read DMA status for INTR & ERROR flags */ 2238c2ecf20Sopenharmony_ci dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); 2248c2ecf20Sopenharmony_ci /* clear INTR & ERROR flags */ 2258c2ecf20Sopenharmony_ci tx4939ide_writeb(dma_stat | ATA_DMA_INTR | ATA_DMA_ERR, base, 2268c2ecf20Sopenharmony_ci TX4939IDE_DMA_Stat); 2278c2ecf20Sopenharmony_ci /* recover intmask cleared by writing to bit2 of DMA_Stat */ 2288c2ecf20Sopenharmony_ci tx4939ide_writew(TX4939IDE_IGNORE_INTS << 8, base, TX4939IDE_Int_Ctl); 2298c2ecf20Sopenharmony_ci return dma_stat; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 2338c2ecf20Sopenharmony_ci/* custom ide_build_dmatable to handle swapped layout */ 2348c2ecf20Sopenharmony_cistatic int tx4939ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 2378c2ecf20Sopenharmony_ci u32 *table = (u32 *)hwif->dmatable_cpu; 2388c2ecf20Sopenharmony_ci unsigned int count = 0; 2398c2ecf20Sopenharmony_ci int i; 2408c2ecf20Sopenharmony_ci struct scatterlist *sg; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) { 2438c2ecf20Sopenharmony_ci u32 cur_addr, cur_len, bcount; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci cur_addr = sg_dma_address(sg); 2468c2ecf20Sopenharmony_ci cur_len = sg_dma_len(sg); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * Fill in the DMA table, without crossing any 64kB boundaries. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci while (cur_len) { 2538c2ecf20Sopenharmony_ci if (count++ >= PRD_ENTRIES) 2548c2ecf20Sopenharmony_ci goto use_pio_instead; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci bcount = 0x10000 - (cur_addr & 0xffff); 2578c2ecf20Sopenharmony_ci if (bcount > cur_len) 2588c2ecf20Sopenharmony_ci bcount = cur_len; 2598c2ecf20Sopenharmony_ci /* 2608c2ecf20Sopenharmony_ci * This workaround for zero count seems required. 2618c2ecf20Sopenharmony_ci * (standard ide_build_dmatable does it too) 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ci if (bcount == 0x10000) 2648c2ecf20Sopenharmony_ci bcount = 0x8000; 2658c2ecf20Sopenharmony_ci *table++ = bcount & 0xffff; 2668c2ecf20Sopenharmony_ci *table++ = cur_addr; 2678c2ecf20Sopenharmony_ci cur_addr += bcount; 2688c2ecf20Sopenharmony_ci cur_len -= bcount; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (count) { 2738c2ecf20Sopenharmony_ci *(table - 2) |= 0x80000000; 2748c2ecf20Sopenharmony_ci return count; 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ciuse_pio_instead: 2788c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: %s\n", drive->name, 2798c2ecf20Sopenharmony_ci count ? "DMA table too small" : "empty DMA table?"); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return 0; /* revert to PIO for this request */ 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci#else 2848c2ecf20Sopenharmony_ci#define tx4939ide_build_dmatable ide_build_dmatable 2858c2ecf20Sopenharmony_ci#endif 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int tx4939ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 2908c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 2918c2ecf20Sopenharmony_ci u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* fall back to PIO! */ 2948c2ecf20Sopenharmony_ci if (tx4939ide_build_dmatable(drive, cmd) == 0) 2958c2ecf20Sopenharmony_ci return 1; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci /* PRD table */ 2988c2ecf20Sopenharmony_ci tx4939ide_writel(hwif->dmatable_dma, base, TX4939IDE_PRD_Ptr); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* specify r/w */ 3018c2ecf20Sopenharmony_ci tx4939ide_writeb(rw, base, TX4939IDE_DMA_Cmd); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* clear INTR & ERROR flags */ 3048c2ecf20Sopenharmony_ci tx4939ide_clear_dma_status(base); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci tx4939ide_writew(SECTOR_SIZE / 2, base, drive->dn ? 3078c2ecf20Sopenharmony_ci TX4939IDE_Xfer_Cnt_2 : TX4939IDE_Xfer_Cnt_1); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci tx4939ide_writew(blk_rq_sectors(cmd->rq), base, TX4939IDE_Sec_Cnt); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci return 0; 3128c2ecf20Sopenharmony_ci} 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_cistatic int tx4939ide_dma_end(ide_drive_t *drive) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 3178c2ecf20Sopenharmony_ci u8 dma_stat, dma_cmd; 3188c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 3198c2ecf20Sopenharmony_ci u16 ctl = tx4939ide_readw(base, TX4939IDE_Int_Ctl); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci /* get DMA command mode */ 3228c2ecf20Sopenharmony_ci dma_cmd = tx4939ide_readb(base, TX4939IDE_DMA_Cmd); 3238c2ecf20Sopenharmony_ci /* stop DMA */ 3248c2ecf20Sopenharmony_ci tx4939ide_writeb(dma_cmd & ~ATA_DMA_START, base, TX4939IDE_DMA_Cmd); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* read and clear the INTR & ERROR bits */ 3278c2ecf20Sopenharmony_ci dma_stat = tx4939ide_clear_dma_status(base); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR) 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* verify good DMA status */ 3328c2ecf20Sopenharmony_ci if ((dma_stat & CHECK_DMA_MASK) == 0 && 3338c2ecf20Sopenharmony_ci (ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) == 3348c2ecf20Sopenharmony_ci (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST)) 3358c2ecf20Sopenharmony_ci /* INT_IDE lost... bug? */ 3368c2ecf20Sopenharmony_ci return 0; 3378c2ecf20Sopenharmony_ci return ((dma_stat & CHECK_DMA_MASK) != 3388c2ecf20Sopenharmony_ci ATA_DMA_INTR) ? 0x10 | dma_stat : 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci/* returns 1 if DMA IRQ issued, 0 otherwise */ 3428c2ecf20Sopenharmony_cistatic int tx4939ide_dma_test_irq(ide_drive_t *drive) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 3458c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 3468c2ecf20Sopenharmony_ci u16 ctl, ide_int; 3478c2ecf20Sopenharmony_ci u8 dma_stat, stat; 3488c2ecf20Sopenharmony_ci int found = 0; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci ctl = tx4939ide_check_error_ints(hwif); 3518c2ecf20Sopenharmony_ci ide_int = ctl & (TX4939IDE_INT_XFEREND | TX4939IDE_INT_HOST); 3528c2ecf20Sopenharmony_ci switch (ide_int) { 3538c2ecf20Sopenharmony_ci case TX4939IDE_INT_HOST: 3548c2ecf20Sopenharmony_ci /* On error, XFEREND might not be asserted. */ 3558c2ecf20Sopenharmony_ci stat = tx4939ide_readb(base, TX4939IDE_AltStat_DevCtl); 3568c2ecf20Sopenharmony_ci if ((stat & (ATA_BUSY | ATA_DRQ | ATA_ERR)) == ATA_ERR) 3578c2ecf20Sopenharmony_ci found = 1; 3588c2ecf20Sopenharmony_ci else 3598c2ecf20Sopenharmony_ci /* Wait for XFEREND (Mask HOST and unmask XFEREND) */ 3608c2ecf20Sopenharmony_ci ctl &= ~TX4939IDE_INT_XFEREND << 8; 3618c2ecf20Sopenharmony_ci ctl |= ide_int << 8; 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci case TX4939IDE_INT_HOST | TX4939IDE_INT_XFEREND: 3648c2ecf20Sopenharmony_ci dma_stat = tx4939ide_readb(base, TX4939IDE_DMA_Stat); 3658c2ecf20Sopenharmony_ci if (!(dma_stat & ATA_DMA_INTR)) 3668c2ecf20Sopenharmony_ci pr_warn("%s: weird interrupt status. " 3678c2ecf20Sopenharmony_ci "DMA_Stat %#02x int_ctl %#04x\n", 3688c2ecf20Sopenharmony_ci hwif->name, dma_stat, ctl); 3698c2ecf20Sopenharmony_ci found = 1; 3708c2ecf20Sopenharmony_ci break; 3718c2ecf20Sopenharmony_ci } 3728c2ecf20Sopenharmony_ci /* 3738c2ecf20Sopenharmony_ci * Do not clear XFEREND, HOST now. They will be cleared by 3748c2ecf20Sopenharmony_ci * clearing bit2 of DMA_Stat. 3758c2ecf20Sopenharmony_ci */ 3768c2ecf20Sopenharmony_ci ctl &= ~ide_int; 3778c2ecf20Sopenharmony_ci tx4939ide_writew(ctl, base, TX4939IDE_Int_Ctl); 3788c2ecf20Sopenharmony_ci return found; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 3828c2ecf20Sopenharmony_cistatic u8 tx4939ide_dma_sff_read_status(ide_hwif_t *hwif) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci return tx4939ide_readb(base, TX4939IDE_DMA_Stat); 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci#else 3898c2ecf20Sopenharmony_ci#define tx4939ide_dma_sff_read_status ide_dma_sff_read_status 3908c2ecf20Sopenharmony_ci#endif 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void tx4939ide_init_hwif(ide_hwif_t *hwif) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci /* Soft Reset */ 3978c2ecf20Sopenharmony_ci tx4939ide_writew(0x8000, base, TX4939IDE_Sys_Ctl); 3988c2ecf20Sopenharmony_ci /* at least 20 GBUSCLK (typ. 100ns @ GBUS200MHz, max 450ns) */ 3998c2ecf20Sopenharmony_ci ndelay(450); 4008c2ecf20Sopenharmony_ci tx4939ide_writew(0x0000, base, TX4939IDE_Sys_Ctl); 4018c2ecf20Sopenharmony_ci /* mask some interrupts and clear all interrupts */ 4028c2ecf20Sopenharmony_ci tx4939ide_writew((TX4939IDE_IGNORE_INTS << 8) | 0xff, base, 4038c2ecf20Sopenharmony_ci TX4939IDE_Int_Ctl); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci tx4939ide_writew(0x0008, base, TX4939IDE_Lo_Burst_Cnt); 4068c2ecf20Sopenharmony_ci tx4939ide_writew(0, base, TX4939IDE_Up_Burst_Cnt); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int tx4939ide_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci hwif->dma_base = 4128c2ecf20Sopenharmony_ci hwif->extra_base + tx4939ide_swizzleb(TX4939IDE_DMA_Cmd); 4138c2ecf20Sopenharmony_ci /* 4148c2ecf20Sopenharmony_ci * Note that we cannot use ATA_DMA_TABLE_OFS, ATA_DMA_STATUS 4158c2ecf20Sopenharmony_ci * for big endian. 4168c2ecf20Sopenharmony_ci */ 4178c2ecf20Sopenharmony_ci return ide_allocate_dma_engine(hwif); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic void tx4939ide_tf_load_fixup(ide_drive_t *drive) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci ide_hwif_t *hwif = drive->hwif; 4238c2ecf20Sopenharmony_ci void __iomem *base = TX4939IDE_BASE(hwif); 4248c2ecf20Sopenharmony_ci u16 sysctl = hwif->select_data >> (drive->dn ? 16 : 0); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * Fix ATA100 CORE System Control Register. (The write to the 4288c2ecf20Sopenharmony_ci * Device/Head register may write wrong data to the System 4298c2ecf20Sopenharmony_ci * Control Register) 4308c2ecf20Sopenharmony_ci * While Sys_Ctl is written here, dev_select() is not needed. 4318c2ecf20Sopenharmony_ci */ 4328c2ecf20Sopenharmony_ci tx4939ide_writew(sysctl, base, TX4939IDE_Sys_Ctl); 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void tx4939ide_tf_load(ide_drive_t *drive, struct ide_taskfile *tf, 4368c2ecf20Sopenharmony_ci u8 valid) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci ide_tf_load(drive, tf, valid); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (valid & IDE_VALID_DEVICE) 4418c2ecf20Sopenharmony_ci tx4939ide_tf_load_fixup(drive); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* custom iops (independent from SWAP_IO_SPACE) */ 4478c2ecf20Sopenharmony_cistatic void tx4939ide_input_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, 4488c2ecf20Sopenharmony_ci void *buf, unsigned int len) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci unsigned long port = drive->hwif->io_ports.data_addr; 4518c2ecf20Sopenharmony_ci unsigned short *ptr = buf; 4528c2ecf20Sopenharmony_ci unsigned int count = (len + 1) / 2; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci while (count--) 4558c2ecf20Sopenharmony_ci *ptr++ = cpu_to_le16(__raw_readw((void __iomem *)port)); 4568c2ecf20Sopenharmony_ci __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void tx4939ide_output_data_swap(ide_drive_t *drive, struct ide_cmd *cmd, 4608c2ecf20Sopenharmony_ci void *buf, unsigned int len) 4618c2ecf20Sopenharmony_ci{ 4628c2ecf20Sopenharmony_ci unsigned long port = drive->hwif->io_ports.data_addr; 4638c2ecf20Sopenharmony_ci unsigned short *ptr = buf; 4648c2ecf20Sopenharmony_ci unsigned int count = (len + 1) / 2; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci while (count--) { 4678c2ecf20Sopenharmony_ci __raw_writew(le16_to_cpu(*ptr), (void __iomem *)port); 4688c2ecf20Sopenharmony_ci ptr++; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci __ide_flush_dcache_range((unsigned long)buf, roundup(len, 2)); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic const struct ide_tp_ops tx4939ide_tp_ops = { 4748c2ecf20Sopenharmony_ci .exec_command = ide_exec_command, 4758c2ecf20Sopenharmony_ci .read_status = ide_read_status, 4768c2ecf20Sopenharmony_ci .read_altstatus = ide_read_altstatus, 4778c2ecf20Sopenharmony_ci .write_devctl = ide_write_devctl, 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci .dev_select = ide_dev_select, 4808c2ecf20Sopenharmony_ci .tf_load = tx4939ide_tf_load, 4818c2ecf20Sopenharmony_ci .tf_read = ide_tf_read, 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci .input_data = tx4939ide_input_data_swap, 4848c2ecf20Sopenharmony_ci .output_data = tx4939ide_output_data_swap, 4858c2ecf20Sopenharmony_ci}; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci#else /* __LITTLE_ENDIAN */ 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic const struct ide_tp_ops tx4939ide_tp_ops = { 4908c2ecf20Sopenharmony_ci .exec_command = ide_exec_command, 4918c2ecf20Sopenharmony_ci .read_status = ide_read_status, 4928c2ecf20Sopenharmony_ci .read_altstatus = ide_read_altstatus, 4938c2ecf20Sopenharmony_ci .write_devctl = ide_write_devctl, 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci .dev_select = ide_dev_select, 4968c2ecf20Sopenharmony_ci .tf_load = tx4939ide_tf_load, 4978c2ecf20Sopenharmony_ci .tf_read = ide_tf_read, 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci .input_data = ide_input_data, 5008c2ecf20Sopenharmony_ci .output_data = ide_output_data, 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci#endif /* __LITTLE_ENDIAN */ 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic const struct ide_port_ops tx4939ide_port_ops = { 5068c2ecf20Sopenharmony_ci .set_pio_mode = tx4939ide_set_pio_mode, 5078c2ecf20Sopenharmony_ci .set_dma_mode = tx4939ide_set_dma_mode, 5088c2ecf20Sopenharmony_ci .clear_irq = tx4939ide_clear_irq, 5098c2ecf20Sopenharmony_ci .cable_detect = tx4939ide_cable_detect, 5108c2ecf20Sopenharmony_ci}; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic const struct ide_dma_ops tx4939ide_dma_ops = { 5138c2ecf20Sopenharmony_ci .dma_host_set = tx4939ide_dma_host_set, 5148c2ecf20Sopenharmony_ci .dma_setup = tx4939ide_dma_setup, 5158c2ecf20Sopenharmony_ci .dma_start = ide_dma_start, 5168c2ecf20Sopenharmony_ci .dma_end = tx4939ide_dma_end, 5178c2ecf20Sopenharmony_ci .dma_test_irq = tx4939ide_dma_test_irq, 5188c2ecf20Sopenharmony_ci .dma_lost_irq = ide_dma_lost_irq, 5198c2ecf20Sopenharmony_ci .dma_timer_expiry = ide_dma_sff_timer_expiry, 5208c2ecf20Sopenharmony_ci .dma_sff_read_status = tx4939ide_dma_sff_read_status, 5218c2ecf20Sopenharmony_ci}; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic const struct ide_port_info tx4939ide_port_info __initconst = { 5248c2ecf20Sopenharmony_ci .init_hwif = tx4939ide_init_hwif, 5258c2ecf20Sopenharmony_ci .init_dma = tx4939ide_init_dma, 5268c2ecf20Sopenharmony_ci .port_ops = &tx4939ide_port_ops, 5278c2ecf20Sopenharmony_ci .dma_ops = &tx4939ide_dma_ops, 5288c2ecf20Sopenharmony_ci .tp_ops = &tx4939ide_tp_ops, 5298c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAG_MMIO, 5308c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, 5318c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 5328c2ecf20Sopenharmony_ci .udma_mask = ATA_UDMA5, 5338c2ecf20Sopenharmony_ci .chipset = ide_generic, 5348c2ecf20Sopenharmony_ci}; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic int __init tx4939ide_probe(struct platform_device *pdev) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct ide_hw hw, *hws[] = { &hw }; 5398c2ecf20Sopenharmony_ci struct ide_host *host; 5408c2ecf20Sopenharmony_ci struct resource *res; 5418c2ecf20Sopenharmony_ci int irq, ret; 5428c2ecf20Sopenharmony_ci unsigned long mapbase; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 5458c2ecf20Sopenharmony_ci if (irq < 0) 5468c2ecf20Sopenharmony_ci return -ENODEV; 5478c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 5488c2ecf20Sopenharmony_ci if (!res) 5498c2ecf20Sopenharmony_ci return -ENODEV; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci if (!devm_request_mem_region(&pdev->dev, res->start, 5528c2ecf20Sopenharmony_ci resource_size(res), MODNAME)) 5538c2ecf20Sopenharmony_ci return -EBUSY; 5548c2ecf20Sopenharmony_ci mapbase = (unsigned long)devm_ioremap(&pdev->dev, res->start, 5558c2ecf20Sopenharmony_ci resource_size(res)); 5568c2ecf20Sopenharmony_ci if (!mapbase) 5578c2ecf20Sopenharmony_ci return -EBUSY; 5588c2ecf20Sopenharmony_ci memset(&hw, 0, sizeof(hw)); 5598c2ecf20Sopenharmony_ci hw.io_ports.data_addr = 5608c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzlew(TX4939IDE_Data); 5618c2ecf20Sopenharmony_ci hw.io_ports.error_addr = 5628c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_Error_Feature); 5638c2ecf20Sopenharmony_ci hw.io_ports.nsect_addr = 5648c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_Sec); 5658c2ecf20Sopenharmony_ci hw.io_ports.lbal_addr = 5668c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_LBA0); 5678c2ecf20Sopenharmony_ci hw.io_ports.lbam_addr = 5688c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_LBA1); 5698c2ecf20Sopenharmony_ci hw.io_ports.lbah_addr = 5708c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_LBA2); 5718c2ecf20Sopenharmony_ci hw.io_ports.device_addr = 5728c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_DevHead); 5738c2ecf20Sopenharmony_ci hw.io_ports.command_addr = 5748c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_Stat_Cmd); 5758c2ecf20Sopenharmony_ci hw.io_ports.ctl_addr = 5768c2ecf20Sopenharmony_ci mapbase + tx4939ide_swizzleb(TX4939IDE_AltStat_DevCtl); 5778c2ecf20Sopenharmony_ci hw.irq = irq; 5788c2ecf20Sopenharmony_ci hw.dev = &pdev->dev; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci pr_info("TX4939 IDE interface (base %#lx, irq %d)\n", mapbase, irq); 5818c2ecf20Sopenharmony_ci host = ide_host_alloc(&tx4939ide_port_info, hws, 1); 5828c2ecf20Sopenharmony_ci if (!host) 5838c2ecf20Sopenharmony_ci return -ENOMEM; 5848c2ecf20Sopenharmony_ci /* use extra_base for base address of the all registers */ 5858c2ecf20Sopenharmony_ci host->ports[0]->extra_base = mapbase; 5868c2ecf20Sopenharmony_ci ret = ide_host_register(host, &tx4939ide_port_info, hws); 5878c2ecf20Sopenharmony_ci if (ret) { 5888c2ecf20Sopenharmony_ci ide_host_free(host); 5898c2ecf20Sopenharmony_ci return ret; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, host); 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int __exit tx4939ide_remove(struct platform_device *pdev) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct ide_host *host = platform_get_drvdata(pdev); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci ide_host_remove(host); 6008c2ecf20Sopenharmony_ci return 0; 6018c2ecf20Sopenharmony_ci} 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 6048c2ecf20Sopenharmony_cistatic int tx4939ide_resume(struct platform_device *dev) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct ide_host *host = platform_get_drvdata(dev); 6078c2ecf20Sopenharmony_ci ide_hwif_t *hwif = host->ports[0]; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci tx4939ide_init_hwif(hwif); 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 6128c2ecf20Sopenharmony_ci#else 6138c2ecf20Sopenharmony_ci#define tx4939ide_resume NULL 6148c2ecf20Sopenharmony_ci#endif 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic struct platform_driver tx4939ide_driver = { 6178c2ecf20Sopenharmony_ci .driver = { 6188c2ecf20Sopenharmony_ci .name = MODNAME, 6198c2ecf20Sopenharmony_ci }, 6208c2ecf20Sopenharmony_ci .remove = __exit_p(tx4939ide_remove), 6218c2ecf20Sopenharmony_ci .resume = tx4939ide_resume, 6228c2ecf20Sopenharmony_ci}; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cimodule_platform_driver_probe(tx4939ide_driver, tx4939ide_probe); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TX4939 internal IDE driver"); 6278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6288c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:tx4939ide"); 629