18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Palmchip bk3710 IDE controller 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006 Texas Instruments. 68c2ecf20Sopenharmony_ci * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * ---------------------------------------------------------------------------- 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * ---------------------------------------------------------------------------- 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/ioport.h> 178c2ecf20Sopenharmony_ci#include <linux/ide.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/init.h> 208c2ecf20Sopenharmony_ci#include <linux/clk.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* Offset of the primary interface registers */ 248c2ecf20Sopenharmony_ci#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* Primary Control Offset */ 278c2ecf20Sopenharmony_ci#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define BK3710_BMICP 0x00 308c2ecf20Sopenharmony_ci#define BK3710_BMISP 0x02 318c2ecf20Sopenharmony_ci#define BK3710_BMIDTP 0x04 328c2ecf20Sopenharmony_ci#define BK3710_IDETIMP 0x40 338c2ecf20Sopenharmony_ci#define BK3710_IDESTATUS 0x47 348c2ecf20Sopenharmony_ci#define BK3710_UDMACTL 0x48 358c2ecf20Sopenharmony_ci#define BK3710_MISCCTL 0x50 368c2ecf20Sopenharmony_ci#define BK3710_REGSTB 0x54 378c2ecf20Sopenharmony_ci#define BK3710_REGRCVR 0x58 388c2ecf20Sopenharmony_ci#define BK3710_DATSTB 0x5C 398c2ecf20Sopenharmony_ci#define BK3710_DATRCVR 0x60 408c2ecf20Sopenharmony_ci#define BK3710_DMASTB 0x64 418c2ecf20Sopenharmony_ci#define BK3710_DMARCVR 0x68 428c2ecf20Sopenharmony_ci#define BK3710_UDMASTB 0x6C 438c2ecf20Sopenharmony_ci#define BK3710_UDMATRP 0x70 448c2ecf20Sopenharmony_ci#define BK3710_UDMAENV 0x74 458c2ecf20Sopenharmony_ci#define BK3710_IORDYTMP 0x78 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic unsigned ideclk_period; /* in nanoseconds */ 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistruct palm_bk3710_udmatiming { 508c2ecf20Sopenharmony_ci unsigned int rptime; /* tRP -- Ready to pause time (nsec) */ 518c2ecf20Sopenharmony_ci unsigned int cycletime; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */ 528c2ecf20Sopenharmony_ci /* tENV is always a minimum of 20 nsec */ 538c2ecf20Sopenharmony_ci}; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = { 568c2ecf20Sopenharmony_ci { 160, 240 / 2 }, /* UDMA Mode 0 */ 578c2ecf20Sopenharmony_ci { 125, 160 / 2 }, /* UDMA Mode 1 */ 588c2ecf20Sopenharmony_ci { 100, 120 / 2 }, /* UDMA Mode 2 */ 598c2ecf20Sopenharmony_ci { 100, 90 / 2 }, /* UDMA Mode 3 */ 608c2ecf20Sopenharmony_ci { 100, 60 / 2 }, /* UDMA Mode 4 */ 618c2ecf20Sopenharmony_ci { 85, 40 / 2 }, /* UDMA Mode 5 */ 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev, 658c2ecf20Sopenharmony_ci unsigned int mode) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci u8 tenv, trp, t0; 688c2ecf20Sopenharmony_ci u32 val32; 698c2ecf20Sopenharmony_ci u16 val16; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci /* DMA Data Setup */ 728c2ecf20Sopenharmony_ci t0 = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].cycletime, 738c2ecf20Sopenharmony_ci ideclk_period) - 1; 748c2ecf20Sopenharmony_ci tenv = DIV_ROUND_UP(20, ideclk_period) - 1; 758c2ecf20Sopenharmony_ci trp = DIV_ROUND_UP(palm_bk3710_udmatimings[mode].rptime, 768c2ecf20Sopenharmony_ci ideclk_period) - 1; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* udmastb Ultra DMA Access Strobe Width */ 798c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8)); 808c2ecf20Sopenharmony_ci val32 |= (t0 << (dev ? 8 : 0)); 818c2ecf20Sopenharmony_ci writel(val32, base + BK3710_UDMASTB); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* udmatrp Ultra DMA Ready to Pause Time */ 848c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8)); 858c2ecf20Sopenharmony_ci val32 |= (trp << (dev ? 8 : 0)); 868c2ecf20Sopenharmony_ci writel(val32, base + BK3710_UDMATRP); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* udmaenv Ultra DMA envelop Time */ 898c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8)); 908c2ecf20Sopenharmony_ci val32 |= (tenv << (dev ? 8 : 0)); 918c2ecf20Sopenharmony_ci writel(val32, base + BK3710_UDMAENV); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* Enable UDMA for Device */ 948c2ecf20Sopenharmony_ci val16 = readw(base + BK3710_UDMACTL) | (1 << dev); 958c2ecf20Sopenharmony_ci writew(val16, base + BK3710_UDMACTL); 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev, 998c2ecf20Sopenharmony_ci unsigned short min_cycle, 1008c2ecf20Sopenharmony_ci unsigned int mode) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci u8 td, tkw, t0; 1038c2ecf20Sopenharmony_ci u32 val32; 1048c2ecf20Sopenharmony_ci u16 val16; 1058c2ecf20Sopenharmony_ci struct ide_timing *t; 1068c2ecf20Sopenharmony_ci int cycletime; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci t = ide_timing_find_mode(mode); 1098c2ecf20Sopenharmony_ci cycletime = max_t(int, t->cycle, min_cycle); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* DMA Data Setup */ 1128c2ecf20Sopenharmony_ci t0 = DIV_ROUND_UP(cycletime, ideclk_period); 1138c2ecf20Sopenharmony_ci td = DIV_ROUND_UP(t->active, ideclk_period); 1148c2ecf20Sopenharmony_ci tkw = t0 - td - 1; 1158c2ecf20Sopenharmony_ci td -= 1; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8)); 1188c2ecf20Sopenharmony_ci val32 |= (td << (dev ? 8 : 0)); 1198c2ecf20Sopenharmony_ci writel(val32, base + BK3710_DMASTB); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8)); 1228c2ecf20Sopenharmony_ci val32 |= (tkw << (dev ? 8 : 0)); 1238c2ecf20Sopenharmony_ci writel(val32, base + BK3710_DMARCVR); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* Disable UDMA for Device */ 1268c2ecf20Sopenharmony_ci val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev); 1278c2ecf20Sopenharmony_ci writew(val16, base + BK3710_UDMACTL); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate, 1318c2ecf20Sopenharmony_ci unsigned int dev, unsigned int cycletime, 1328c2ecf20Sopenharmony_ci unsigned int mode) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci u8 t2, t2i, t0; 1358c2ecf20Sopenharmony_ci u32 val32; 1368c2ecf20Sopenharmony_ci struct ide_timing *t; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci t = ide_timing_find_mode(XFER_PIO_0 + mode); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* PIO Data Setup */ 1418c2ecf20Sopenharmony_ci t0 = DIV_ROUND_UP(cycletime, ideclk_period); 1428c2ecf20Sopenharmony_ci t2 = DIV_ROUND_UP(t->active, ideclk_period); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci t2i = t0 - t2 - 1; 1458c2ecf20Sopenharmony_ci t2 -= 1; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8)); 1488c2ecf20Sopenharmony_ci val32 |= (t2 << (dev ? 8 : 0)); 1498c2ecf20Sopenharmony_ci writel(val32, base + BK3710_DATSTB); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8)); 1528c2ecf20Sopenharmony_ci val32 |= (t2i << (dev ? 8 : 0)); 1538c2ecf20Sopenharmony_ci writel(val32, base + BK3710_DATRCVR); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if (mate) { 1568c2ecf20Sopenharmony_ci u8 mode2 = mate->pio_mode - XFER_PIO_0; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (mode2 < mode) 1598c2ecf20Sopenharmony_ci mode = mode2; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* TASKFILE Setup */ 1638c2ecf20Sopenharmony_ci t0 = DIV_ROUND_UP(t->cyc8b, ideclk_period); 1648c2ecf20Sopenharmony_ci t2 = DIV_ROUND_UP(t->act8b, ideclk_period); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci t2i = t0 - t2 - 1; 1678c2ecf20Sopenharmony_ci t2 -= 1; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8)); 1708c2ecf20Sopenharmony_ci val32 |= (t2 << (dev ? 8 : 0)); 1718c2ecf20Sopenharmony_ci writel(val32, base + BK3710_REGSTB); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8)); 1748c2ecf20Sopenharmony_ci val32 |= (t2i << (dev ? 8 : 0)); 1758c2ecf20Sopenharmony_ci writel(val32, base + BK3710_REGRCVR); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void palm_bk3710_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci int is_slave = drive->dn & 1; 1818c2ecf20Sopenharmony_ci void __iomem *base = (void __iomem *)hwif->dma_base; 1828c2ecf20Sopenharmony_ci const u8 xferspeed = drive->dma_mode; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci if (xferspeed >= XFER_UDMA_0) { 1858c2ecf20Sopenharmony_ci palm_bk3710_setudmamode(base, is_slave, 1868c2ecf20Sopenharmony_ci xferspeed - XFER_UDMA_0); 1878c2ecf20Sopenharmony_ci } else { 1888c2ecf20Sopenharmony_ci palm_bk3710_setdmamode(base, is_slave, 1898c2ecf20Sopenharmony_ci drive->id[ATA_ID_EIDE_DMA_MIN], 1908c2ecf20Sopenharmony_ci xferspeed); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic void palm_bk3710_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci unsigned int cycle_time; 1978c2ecf20Sopenharmony_ci int is_slave = drive->dn & 1; 1988c2ecf20Sopenharmony_ci ide_drive_t *mate; 1998c2ecf20Sopenharmony_ci void __iomem *base = (void __iomem *)hwif->dma_base; 2008c2ecf20Sopenharmony_ci const u8 pio = drive->pio_mode - XFER_PIO_0; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * Obtain the drive PIO data for tuning the Palm Chip registers 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_ci cycle_time = ide_pio_cycle_time(drive, pio); 2068c2ecf20Sopenharmony_ci mate = ide_get_pair_dev(drive); 2078c2ecf20Sopenharmony_ci palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio); 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void palm_bk3710_chipinit(void __iomem *base) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * REVISIT: the ATA reset signal needs to be managed through a 2148c2ecf20Sopenharmony_ci * GPIO, which means it should come from platform_data. Until 2158c2ecf20Sopenharmony_ci * we get and use such information, we have to trust that things 2168c2ecf20Sopenharmony_ci * have been reset before we get here. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * Program the IDETIMP Register Value based on the following assumptions 2218c2ecf20Sopenharmony_ci * 2228c2ecf20Sopenharmony_ci * (ATA_IDETIMP_IDEEN , ENABLE ) | 2238c2ecf20Sopenharmony_ci * (ATA_IDETIMP_PREPOST1 , DISABLE) | 2248c2ecf20Sopenharmony_ci * (ATA_IDETIMP_PREPOST0 , DISABLE) | 2258c2ecf20Sopenharmony_ci * 2268c2ecf20Sopenharmony_ci * DM6446 silicon rev 2.1 and earlier have no observed net benefit 2278c2ecf20Sopenharmony_ci * from enabling prefetch/postwrite. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_ci writew(BIT(15), base + BK3710_IDETIMP); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * UDMACTL Ultra-ATA DMA Control 2338c2ecf20Sopenharmony_ci * (ATA_UDMACTL_UDMAP1 , 0 ) | 2348c2ecf20Sopenharmony_ci * (ATA_UDMACTL_UDMAP0 , 0 ) 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci writew(0, base + BK3710_UDMACTL); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* 2408c2ecf20Sopenharmony_ci * MISCCTL Miscellaneous Conrol Register 2418c2ecf20Sopenharmony_ci * (ATA_MISCCTL_HWNHLD1P , 1 cycle) 2428c2ecf20Sopenharmony_ci * (ATA_MISCCTL_HWNHLD0P , 1 cycle) 2438c2ecf20Sopenharmony_ci * (ATA_MISCCTL_TIMORIDE , 1) 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_ci writel(0x001, base + BK3710_MISCCTL); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * IORDYTMP IORDY Timer for Primary Register 2498c2ecf20Sopenharmony_ci * (ATA_IORDYTMP_IORDYTMP , 0xffff ) 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci writel(0xFFFF, base + BK3710_IORDYTMP); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* 2548c2ecf20Sopenharmony_ci * Configure BMISP Register 2558c2ecf20Sopenharmony_ci * (ATA_BMISP_DMAEN1 , DISABLE ) | 2568c2ecf20Sopenharmony_ci * (ATA_BMISP_DMAEN0 , DISABLE ) | 2578c2ecf20Sopenharmony_ci * (ATA_BMISP_IORDYINT , CLEAR) | 2588c2ecf20Sopenharmony_ci * (ATA_BMISP_INTRSTAT , CLEAR) | 2598c2ecf20Sopenharmony_ci * (ATA_BMISP_DMAERROR , CLEAR) 2608c2ecf20Sopenharmony_ci */ 2618c2ecf20Sopenharmony_ci writew(0, base + BK3710_BMISP); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci palm_bk3710_setpiomode(base, NULL, 0, 600, 0); 2648c2ecf20Sopenharmony_ci palm_bk3710_setpiomode(base, NULL, 1, 600, 0); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic u8 palm_bk3710_cable_detect(ide_hwif_t *hwif) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci return ATA_CBL_PATA80; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int palm_bk3710_init_dma(ide_hwif_t *hwif, const struct ide_port_info *d) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (ide_allocate_dma_engine(hwif)) 2778c2ecf20Sopenharmony_ci return -1; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci hwif->dma_base = hwif->io_ports.data_addr - IDE_PALM_ATA_PRI_REG_OFFSET; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic const struct ide_port_ops palm_bk3710_ports_ops = { 2858c2ecf20Sopenharmony_ci .set_pio_mode = palm_bk3710_set_pio_mode, 2868c2ecf20Sopenharmony_ci .set_dma_mode = palm_bk3710_set_dma_mode, 2878c2ecf20Sopenharmony_ci .cable_detect = palm_bk3710_cable_detect, 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic struct ide_port_info palm_bk3710_port_info __initdata = { 2918c2ecf20Sopenharmony_ci .init_dma = palm_bk3710_init_dma, 2928c2ecf20Sopenharmony_ci .port_ops = &palm_bk3710_ports_ops, 2938c2ecf20Sopenharmony_ci .dma_ops = &sff_dma_ops, 2948c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAG_MMIO, 2958c2ecf20Sopenharmony_ci .pio_mask = ATA_PIO4, 2968c2ecf20Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 2978c2ecf20Sopenharmony_ci .chipset = ide_palm3710, 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic int __init palm_bk3710_probe(struct platform_device *pdev) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct clk *clk; 3038c2ecf20Sopenharmony_ci struct resource *mem, *irq; 3048c2ecf20Sopenharmony_ci void __iomem *base; 3058c2ecf20Sopenharmony_ci unsigned long rate, mem_size; 3068c2ecf20Sopenharmony_ci int i, rc; 3078c2ecf20Sopenharmony_ci struct ide_hw hw, *hws[] = { &hw }; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci clk = clk_get(&pdev->dev, NULL); 3108c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 3118c2ecf20Sopenharmony_ci return -ENODEV; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci clk_enable(clk); 3148c2ecf20Sopenharmony_ci rate = clk_get_rate(clk); 3158c2ecf20Sopenharmony_ci if (!rate) 3168c2ecf20Sopenharmony_ci return -EINVAL; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* NOTE: round *down* to meet minimum timings; we count in clocks */ 3198c2ecf20Sopenharmony_ci ideclk_period = 1000000000UL / rate; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3228c2ecf20Sopenharmony_ci if (mem == NULL) { 3238c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to get memory region resource\n"); 3248c2ecf20Sopenharmony_ci return -ENODEV; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 3288c2ecf20Sopenharmony_ci if (irq == NULL) { 3298c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to get IRQ resource\n"); 3308c2ecf20Sopenharmony_ci return -ENODEV; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci mem_size = resource_size(mem); 3348c2ecf20Sopenharmony_ci if (request_mem_region(mem->start, mem_size, "palm_bk3710") == NULL) { 3358c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to request memory region\n"); 3368c2ecf20Sopenharmony_ci return -EBUSY; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci base = ioremap(mem->start, mem_size); 3408c2ecf20Sopenharmony_ci if (!base) { 3418c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to map IO memory\n"); 3428c2ecf20Sopenharmony_ci release_mem_region(mem->start, mem_size); 3438c2ecf20Sopenharmony_ci return -ENOMEM; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Configure the Palm Chip controller */ 3478c2ecf20Sopenharmony_ci palm_bk3710_chipinit(base); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci memset(&hw, 0, sizeof(hw)); 3508c2ecf20Sopenharmony_ci for (i = 0; i < IDE_NR_PORTS - 2; i++) 3518c2ecf20Sopenharmony_ci hw.io_ports_array[i] = (unsigned long) 3528c2ecf20Sopenharmony_ci (base + IDE_PALM_ATA_PRI_REG_OFFSET + i); 3538c2ecf20Sopenharmony_ci hw.io_ports.ctl_addr = (unsigned long) 3548c2ecf20Sopenharmony_ci (base + IDE_PALM_ATA_PRI_CTL_OFFSET); 3558c2ecf20Sopenharmony_ci hw.irq = irq->start; 3568c2ecf20Sopenharmony_ci hw.dev = &pdev->dev; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci palm_bk3710_port_info.udma_mask = rate < 100000000 ? ATA_UDMA4 : 3598c2ecf20Sopenharmony_ci ATA_UDMA5; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* Register the IDE interface with Linux */ 3628c2ecf20Sopenharmony_ci rc = ide_host_add(&palm_bk3710_port_info, hws, 1, NULL); 3638c2ecf20Sopenharmony_ci if (rc) 3648c2ecf20Sopenharmony_ci goto out; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ciout: 3688c2ecf20Sopenharmony_ci printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n"); 3698c2ecf20Sopenharmony_ci return rc; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* work with hotplug and coldplug */ 3738c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:palm_bk3710"); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic struct platform_driver platform_bk_driver = { 3768c2ecf20Sopenharmony_ci .driver = { 3778c2ecf20Sopenharmony_ci .name = "palm_bk3710", 3788c2ecf20Sopenharmony_ci }, 3798c2ecf20Sopenharmony_ci}; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_cistatic int __init palm_bk3710_init(void) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci return platform_driver_probe(&platform_bk_driver, palm_bk3710_probe); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cimodule_init(palm_bk3710_init); 3878c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 388