| 1 | From 8e46c06091fd87904205a977be3c784e3ac61e95 Mon Sep 17 00:00:00 2001 |
| 2 | From: Jingchang Lu <b35083@freescale.com> |
| 3 | Date: Thu, 4 Aug 2011 09:59:48 +0800 |
| 4 | Subject: [PATCH 37/52] Add ColdFire MCF54455 PATA interface support |
| 5 | |
| 6 | ColdFire MCF54455 parallel ATA controller support |
| 7 | both uDMA and PIO mode, this driver implements all. |
| 8 | |
| 9 | Signed-off-by: Jingchang Lu <b35083@freescale.com> |
| 10 | --- |
| 11 | arch/m68k/include/asm/pata_fsl.h | 17 + |
| 12 | drivers/ata/Kconfig | 23 +- |
| 13 | drivers/ata/Makefile | 1 + |
| 14 | drivers/ata/pata_fsl.c | 844 ++++++++++++++++++++++++++++++++++++++ |
| 15 | 4 files changed, 884 insertions(+), 1 deletions(-) |
| 16 | create mode 100644 arch/m68k/include/asm/pata_fsl.h |
| 17 | create mode 100644 drivers/ata/pata_fsl.c |
| 18 | |
| 19 | --- /dev/null |
| 20 | +++ b/arch/m68k/include/asm/pata_fsl.h |
| 21 | @@ -0,0 +1,17 @@ |
| 22 | +/* |
| 23 | + * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. |
| 24 | + * |
| 25 | + * This file is subject to the terms and conditions of the GNU General Public |
| 26 | + * License. See the file COPYING in the main directory of this archive |
| 27 | + * for more details. |
| 28 | + */ |
| 29 | + |
| 30 | +#ifndef _ASM_M68K_PATA_FSL_H |
| 31 | +#define _ASM_M68K_PATA_FSL_H |
| 32 | + |
| 33 | +/* ATA mapped IO address translate function */ |
| 34 | +extern unsigned int io_ata_virt2phys(void *x); |
| 35 | +extern void *io_ata_phys2virt(unsigned int x); |
| 36 | + |
| 37 | + |
| 38 | +#endif |
| 39 | --- a/drivers/ata/Kconfig |
| 40 | +++ b/drivers/ata/Kconfig |
| 41 | @@ -14,7 +14,7 @@ menuconfig ATA |
| 42 | tristate "Serial ATA and Parallel ATA drivers" |
| 43 | depends on HAS_IOMEM |
| 44 | depends on BLOCK |
| 45 | - depends on !(M32R || M68K) || BROKEN |
| 46 | + depends on !(M32R) || BROKEN |
| 47 | select SCSI |
| 48 | ---help--- |
| 49 | If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or |
| 50 | @@ -687,6 +687,27 @@ config PATA_WINBOND |
| 51 | |
| 52 | If unsure, say N. |
| 53 | |
| 54 | +config PATA_FSL |
| 55 | + tristate "Freescale on-chip PATA support" |
| 56 | + depends on (ARCH_MX3 || ARCH_MX27 || PPC_512x || M54455) |
| 57 | + help |
| 58 | + Some Freescale processors SOC have parallel ATA controller, |
| 59 | + such as ColdFire MCF54455. |
| 60 | + |
| 61 | + Say Y here if you wish to use the on-chip ATA interface. |
| 62 | + |
| 63 | + If you are unsure, say N to this. |
| 64 | + |
| 65 | +config FSL_PATA_USE_DMA |
| 66 | + bool "Freescale PATA eDMA support" |
| 67 | + depends on PATA_FSL && COLDFIRE_EDMA |
| 68 | + default y |
| 69 | + help |
| 70 | + This option enables the uDMA support over PATA interface |
| 71 | + which can improve performance than PIO mode for read and write. |
| 72 | + |
| 73 | + If unsure, say Y. |
| 74 | + |
| 75 | endif # ATA_BMDMA |
| 76 | |
| 77 | comment "PIO-only SFF controllers" |
| 78 | --- a/drivers/ata/Makefile |
| 79 | +++ b/drivers/ata/Makefile |
| 80 | @@ -72,6 +72,7 @@ obj-$(CONFIG_PATA_TOSHIBA) += pata_picco |
| 81 | obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o |
| 82 | obj-$(CONFIG_PATA_VIA) += pata_via.o |
| 83 | obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o |
| 84 | +obj-$(CONFIG_PATA_FSL) += pata_fsl.o |
| 85 | |
| 86 | # SFF PIO only |
| 87 | obj-$(CONFIG_PATA_AT32) += pata_at32.o |
| 88 | --- /dev/null |
| 89 | +++ b/drivers/ata/pata_fsl.c |
| 90 | @@ -0,0 +1,844 @@ |
| 91 | +/* |
| 92 | + * Freescale integrated PATA driver |
| 93 | + * |
| 94 | + * Copyright (C) 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. |
| 95 | + * |
| 96 | + * Description: |
| 97 | + * This driver is for Coldfire MCF54455 on-chip ATA module. |
| 98 | + * |
| 99 | + * This is free software; you can redistribute it and/or modify it |
| 100 | + * under the GNU General Public License as published by the Free |
| 101 | + * Software Foundation; either version 2 of the License, or (at |
| 102 | + * your option) any later version. |
| 103 | + * |
| 104 | + */ |
| 105 | + |
| 106 | +#include <linux/kernel.h> |
| 107 | +#include <linux/module.h> |
| 108 | +#include <linux/init.h> |
| 109 | +#include <linux/blkdev.h> |
| 110 | +#include <scsi/scsi_host.h> |
| 111 | +#include <linux/ata.h> |
| 112 | +#include <linux/libata.h> |
| 113 | +#include <linux/platform_device.h> |
| 114 | +#include <linux/fsl_devices.h> |
| 115 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 116 | +#include <asm/mcf_edma.h> |
| 117 | +#endif |
| 118 | +#include <asm/pata_fsl.h> |
| 119 | + |
| 120 | +#define DRV_NAME "pata_fsl" |
| 121 | +#define DRV_VERSION "1.0" |
| 122 | + |
| 123 | +#ifdef CONFIG_M54455 |
| 124 | +#define WRITE_ATA8(val, reg) \ |
| 125 | + __raw_writeb(val, (ata_regs + reg)); |
| 126 | +#define WRITE_ATA16(val, reg) \ |
| 127 | + __raw_writew(val, (ata_regs + reg)); |
| 128 | +#else |
| 129 | +#define WRITE_ATA8(val, reg) \ |
| 130 | + __raw_writel(val, (ata_regs + reg)); |
| 131 | +#define WRITE_ATA16(val, reg) \ |
| 132 | + __raw_writel(val, (ata_regs + reg)); |
| 133 | +#endif |
| 134 | + |
| 135 | +#define MAX_FSL_SG 256 /* MCF_EDMA_TCD_PER_CHAN */ |
| 136 | + |
| 137 | +struct pata_fsl_priv { |
| 138 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 139 | + int ultra; |
| 140 | +#endif |
| 141 | + u8 *fsl_ata_regs; |
| 142 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 143 | + int dma_rchan; |
| 144 | + int dma_wchan; |
| 145 | + int dma_done; |
| 146 | + int dma_dir; |
| 147 | +#if 0 |
| 148 | + int nsg; |
| 149 | + struct fsl_edma_requestbuf reqbuf[MAX_FSL_SG]; |
| 150 | +#endif |
| 151 | +#endif |
| 152 | +}; |
| 153 | + |
| 154 | +enum { |
| 155 | + /* various constants */ |
| 156 | + |
| 157 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 158 | + FSL_ATA_MAX_SG_LEN = 65534, |
| 159 | +#endif |
| 160 | + |
| 161 | + /* offsets to registers */ |
| 162 | + |
| 163 | + FSL_ATA_TIMING_REGS = 0x00, |
| 164 | + FSL_ATA_FIFO_FILL = 0x20, |
| 165 | + FSL_ATA_CONTROL = 0x24, |
| 166 | + FSL_ATA_INT_PEND = 0x28, |
| 167 | + FSL_ATA_INT_EN = 0x2C, |
| 168 | + FSL_ATA_INT_CLEAR = 0x30, |
| 169 | + FSL_ATA_FIFO_ALARM = 0x34, |
| 170 | + FSL_ATA_DRIVE_DATA = 0xA0, |
| 171 | + FSL_ATA_DRIVE_CONTROL = 0xD8, |
| 172 | + |
| 173 | + /* bits within FSL_ATA_CONTROL */ |
| 174 | + |
| 175 | + FSL_ATA_CTRL_FIFO_RST_B = 0x80, |
| 176 | + FSL_ATA_CTRL_ATA_RST_B = 0x40, |
| 177 | + FSL_ATA_CTRL_FIFO_TX_EN = 0x20, |
| 178 | + FSL_ATA_CTRL_FIFO_RCV_EN = 0x10, |
| 179 | + FSL_ATA_CTRL_DMA_PENDING = 0x08, |
| 180 | + FSL_ATA_CTRL_DMA_ULTRA = 0x04, |
| 181 | + FSL_ATA_CTRL_DMA_WRITE = 0x02, |
| 182 | + FSL_ATA_CTRL_IORDY_EN = 0x01, |
| 183 | + |
| 184 | + /* bits within the interrupt control registers */ |
| 185 | + |
| 186 | + FSL_ATA_INTR_ATA_INTRQ1 = 0x80, |
| 187 | + FSL_ATA_INTR_FIFO_UNDERFLOW = 0x40, |
| 188 | + FSL_ATA_INTR_FIFO_OVERFLOW = 0x20, |
| 189 | + FSL_ATA_INTR_CTRL_IDLE = 0x10, |
| 190 | + FSL_ATA_INTR_ATA_INTRQ2 = 0x08, |
| 191 | +}; |
| 192 | + |
| 193 | +/* |
| 194 | + * This structure contains the timing parameters for |
| 195 | + * ATA bus timing in the 5 PIO modes. The timings |
| 196 | + * are in nanoseconds, and are converted to clock |
| 197 | + * cycles before being stored in the ATA controller |
| 198 | + * timing registers. |
| 199 | + */ |
| 200 | +static struct { |
| 201 | + short t0, t1, t2_8, t2_16, t2i, t4, t9, tA; |
| 202 | +} pio_specs[] = { |
| 203 | + [0] = { |
| 204 | + .t0 = 600, .t1 = 70, .t2_8 = 290, .t2_16 = 165, .t2i = 0, |
| 205 | + .t4 = 30, .t9 = 20, .tA = 50 |
| 206 | + }, |
| 207 | + [1] = { |
| 208 | + .t0 = 383, .t1 = 50, .t2_8 = 290, .t2_16 = 125, .t2i = 0, |
| 209 | + .t4 = 20, .t9 = 15, .tA = 50 |
| 210 | + }, |
| 211 | + [2] = { |
| 212 | + .t0 = 240, .t1 = 30, .t2_8 = 290, .t2_16 = 100, .t2i = 0, |
| 213 | + .t4 = 15, .t9 = 10, .tA = 50 |
| 214 | + }, |
| 215 | + [3] = { |
| 216 | + .t0 = 180, .t1 = 30, .t2_8 = 80, .t2_16 = 80, .t2i = 0, |
| 217 | + .t4 = 10, .t9 = 10, .tA = 50 |
| 218 | + }, |
| 219 | + [4] = { |
| 220 | + .t0 = 120, .t1 = 25, .t2_8 = 70, .t2_16 = 70, .t2i = 0, |
| 221 | + .t4 = 10, .t9 = 10, .tA = 50 |
| 222 | + }, |
| 223 | +}; |
| 224 | + |
| 225 | +#define NR_PIO_SPECS (sizeof pio_specs / sizeof pio_specs[0]) |
| 226 | + |
| 227 | +/* |
| 228 | + * This structure contains the timing parameters for |
| 229 | + * ATA bus timing in the 3 MDMA modes. The timings |
| 230 | + * are in nanoseconds, and are converted to clock |
| 231 | + * cycles before being stored in the ATA controller |
| 232 | + * timing registers. |
| 233 | + */ |
| 234 | +static struct { |
| 235 | + short t0M, tD, tH, tJ, tKW, tM, tN, tJNH; |
| 236 | +} mdma_specs[] = { |
| 237 | + [0] = { |
| 238 | + .t0M = 480, .tD = 215, .tH = 20, .tJ = 20, .tKW = 215, |
| 239 | + .tM = 50, .tN = 15, .tJNH = 20 |
| 240 | + }, |
| 241 | + [1] = { |
| 242 | + .t0M = 150, .tD = 80, .tH = 15, .tJ = 5, .tKW = 50, |
| 243 | + .tM = 30, .tN = 10, .tJNH = 15 |
| 244 | + }, |
| 245 | + [2] = { |
| 246 | + .t0M = 120, .tD = 70, .tH = 10, .tJ = 5, .tKW = 25, |
| 247 | + .tM = 25, .tN = 10, .tJNH = 10 |
| 248 | + }, |
| 249 | +}; |
| 250 | + |
| 251 | +#define NR_MDMA_SPECS (sizeof mdma_specs / sizeof mdma_specs[0]) |
| 252 | + |
| 253 | +/* |
| 254 | + * This structure contains the timing parameters for |
| 255 | + * ATA bus timing in the 6 UDMA modes. The timings |
| 256 | + * are in nanoseconds, and are converted to clock |
| 257 | + * cycles before being stored in the ATA controller |
| 258 | + * timing registers. |
| 259 | + */ |
| 260 | +static struct { |
| 261 | + short t2CYC, tCYC, tDS, tDH, tDVS, tDVH, tCVS, tCVH, tFS_min, tLI_max, |
| 262 | + tMLI, tAZ, tZAH, tENV_min, tSR, tRFS, tRP, tACK, tSS, tDZFS; |
| 263 | +} udma_specs[] = { |
| 264 | + [0] = { |
| 265 | + .t2CYC = 235, .tCYC = 114, .tDS = 15, .tDH = 5, .tDVS = 70, |
| 266 | + .tDVH = 6, .tCVS = 70, .tCVH = 6, .tFS_min = 0, |
| 267 | + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, |
| 268 | + .tENV_min = 20, .tSR = 50, .tRFS = 75, .tRP = 160, |
| 269 | + .tACK = 20, .tSS = 50, .tDZFS = 80 |
| 270 | + }, |
| 271 | + [1] = { |
| 272 | + .t2CYC = 156, .tCYC = 75, .tDS = 10, .tDH = 5, .tDVS = 48, |
| 273 | + .tDVH = 6, .tCVS = 48, .tCVH = 6, .tFS_min = 0, |
| 274 | + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, |
| 275 | + .tENV_min = 20, .tSR = 30, .tRFS = 70, .tRP = 125, |
| 276 | + .tACK = 20, .tSS = 50, .tDZFS = 63 |
| 277 | + }, |
| 278 | + [2] = { |
| 279 | + .t2CYC = 117, .tCYC = 55, .tDS = 7, .tDH = 5, .tDVS = 34, |
| 280 | + .tDVH = 6, .tCVS = 34, .tCVH = 6, .tFS_min = 0, |
| 281 | + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, |
| 282 | + .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100, |
| 283 | + .tACK = 20, .tSS = 50, .tDZFS = 47 |
| 284 | + }, |
| 285 | + [3] = { |
| 286 | + .t2CYC = 86, .tCYC = 39, .tDS = 7, .tDH = 5, .tDVS = 20, |
| 287 | + .tDVH = 6, .tCVS = 20, .tCVH = 6, .tFS_min = 0, |
| 288 | + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, |
| 289 | + .tENV_min = 20, .tSR = 20, .tRFS = 60, .tRP = 100, |
| 290 | + .tACK = 20, .tSS = 50, .tDZFS = 35 |
| 291 | + }, |
| 292 | + [4] = { |
| 293 | + .t2CYC = 57, .tCYC = 25, .tDS = 5, .tDH = 5, .tDVS = 7, |
| 294 | + .tDVH = 6, .tCVS = 7, .tCVH = 6, .tFS_min = 0, |
| 295 | + .tLI_max = 100, .tMLI = 20, .tAZ = 10, .tZAH = 20, |
| 296 | + .tENV_min = 20, .tSR = 50, .tRFS = 60, .tRP = 100, |
| 297 | + .tACK = 20, .tSS = 50, .tDZFS = 25 |
| 298 | + }, |
| 299 | + [5] = { |
| 300 | + .t2CYC = 38, .tCYC = 17, .tDS = 4, .tDH = 5, .tDVS = 5, |
| 301 | + .tDVH = 6, .tCVS = 10, .tCVH = 10, .tFS_min = 0, |
| 302 | + .tLI_max = 75, .tMLI = 20, .tAZ = 10, .tZAH = 20, |
| 303 | + .tENV_min = 20, .tSR = 20, .tRFS = 50, .tRP = 85, |
| 304 | + .tACK = 20, .tSS = 50, .tDZFS = 40 |
| 305 | + }, |
| 306 | +}; |
| 307 | + |
| 308 | +#define NR_UDMA_SPECS (sizeof udma_specs / sizeof udma_specs[0]) |
| 309 | + |
| 310 | +struct fsl_ata_time_regs { |
| 311 | + u8 time_off, time_on, time_1, time_2w; |
| 312 | + u8 time_2r, time_ax, time_pio_rdx, time_4; |
| 313 | + u8 time_9, time_m, time_jn, time_d; |
| 314 | + u8 time_k, time_ack, time_env, time_rpx; |
| 315 | + u8 time_zah, time_mlix, time_dvh, time_dzfs; |
| 316 | + u8 time_dvs, time_cvh, time_ss, time_cyc; |
| 317 | +} __packed; |
| 318 | + |
| 319 | + |
| 320 | +static void update_timing_config(struct fsl_ata_time_regs *tp, |
| 321 | + struct ata_host *host) |
| 322 | +{ |
| 323 | + u32 __iomem *lp = (u32 __iomem *)tp; |
| 324 | + struct pata_fsl_priv *priv = host->private_data; |
| 325 | + u32 __iomem *ctlp = (u32 __iomem *)priv->fsl_ata_regs; |
| 326 | + int i; |
| 327 | + |
| 328 | + /* |
| 329 | + * JKM - this could have endianess issues on BE depending |
| 330 | + * on how the controller is glued to the bus -- probably |
| 331 | + * should rewrite this to write byte at a time. |
| 332 | + */ |
| 333 | + for (i = 0; i < 6; i++) { |
| 334 | + __raw_writel(*lp, ctlp); |
| 335 | + lp++; |
| 336 | + ctlp++; |
| 337 | + } |
| 338 | +} |
| 339 | + |
| 340 | +/*! |
| 341 | + * Calculate values for the ATA bus timing registers and store |
| 342 | + * them into the hardware. |
| 343 | + * |
| 344 | + * @param xfer_mode specifies XFER xfer_mode |
| 345 | + * @param pdev specifies platform_device |
| 346 | + * |
| 347 | + * @return EINVAL speed out of range, or illegal mode |
| 348 | + */ |
| 349 | +static int set_ata_bus_timing(u8 xfer_mode, struct platform_device *pdev) |
| 350 | +{ |
| 351 | + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) |
| 352 | + pdev->dev.platform_data; |
| 353 | + struct ata_host *host = dev_get_drvdata(&pdev->dev); |
| 354 | + |
| 355 | + /* get the bus clock cycle time, in ns */ |
| 356 | + int T = 1 * 1000 * 1000 * 1000 / plat->get_clk_rate(); |
| 357 | + struct fsl_ata_time_regs tr = {0}; |
| 358 | + DPRINTK("clk_rate = %d T = %d\n", plat->get_clk_rate(), T); |
| 359 | + |
| 360 | + /* |
| 361 | + * every mode gets the same t_off and t_on |
| 362 | + */ |
| 363 | + tr.time_off = 3; |
| 364 | + tr.time_on = 3; |
| 365 | + |
| 366 | + if (xfer_mode >= XFER_UDMA_0) { |
| 367 | + int speed = xfer_mode - XFER_UDMA_0; |
| 368 | + if (speed >= NR_UDMA_SPECS) |
| 369 | + return -EINVAL; |
| 370 | + |
| 371 | + tr.time_ack = (udma_specs[speed].tACK + T) / T; |
| 372 | + tr.time_env = (udma_specs[speed].tENV_min + T) / T; |
| 373 | + tr.time_rpx = (udma_specs[speed].tRP + T) / T + 2; |
| 374 | + |
| 375 | + tr.time_zah = (udma_specs[speed].tZAH + T) / T; |
| 376 | + tr.time_mlix = (udma_specs[speed].tMLI + T) / T; |
| 377 | + tr.time_dvh = (udma_specs[speed].tDVH + T) / T + 1; |
| 378 | + tr.time_dzfs = (udma_specs[speed].tDZFS + T) / T; |
| 379 | + |
| 380 | + tr.time_dvs = (udma_specs[speed].tDVS + T) / T; |
| 381 | + tr.time_cvh = (udma_specs[speed].tCVH + T) / T; |
| 382 | + tr.time_ss = (udma_specs[speed].tSS + T) / T; |
| 383 | + tr.time_cyc = (udma_specs[speed].tCYC + T) / T; |
| 384 | + } else if (xfer_mode >= XFER_MW_DMA_0) { |
| 385 | + int speed = xfer_mode - XFER_MW_DMA_0; |
| 386 | + if (speed >= NR_MDMA_SPECS) |
| 387 | + return -EINVAL; |
| 388 | + |
| 389 | + tr.time_m = (mdma_specs[speed].tM + T) / T; |
| 390 | + tr.time_jn = (mdma_specs[speed].tJNH + T) / T; |
| 391 | + tr.time_d = (mdma_specs[speed].tD + T) / T; |
| 392 | + |
| 393 | + tr.time_k = (mdma_specs[speed].tKW + T) / T; |
| 394 | + } else { |
| 395 | + int speed = xfer_mode - XFER_PIO_0; |
| 396 | + if (speed >= NR_PIO_SPECS) |
| 397 | + return -EINVAL; |
| 398 | + |
| 399 | + tr.time_1 = (pio_specs[speed].t1 + T) / T; |
| 400 | + tr.time_2w = (pio_specs[speed].t2_8 + T) / T; |
| 401 | + |
| 402 | + tr.time_2r = (pio_specs[speed].t2_8 + T) / T; |
| 403 | + tr.time_ax = (pio_specs[speed].tA + T) / T + 2; |
| 404 | + tr.time_pio_rdx = 1; |
| 405 | + tr.time_4 = (pio_specs[speed].t4 + T) / T; |
| 406 | + |
| 407 | + tr.time_9 = (pio_specs[speed].t9 + T) / T; |
| 408 | + } |
| 409 | + |
| 410 | + update_timing_config(&tr, host); |
| 411 | + |
| 412 | + return 0; |
| 413 | +} |
| 414 | + |
| 415 | +static void pata_fsl_set_piomode(struct ata_port *ap, struct ata_device *adev) |
| 416 | +{ |
| 417 | + set_ata_bus_timing(adev->pio_mode, to_platform_device(ap->dev)); |
| 418 | +} |
| 419 | + |
| 420 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 421 | +static void pata_fsl_set_dmamode(struct ata_port *ap, struct ata_device *adev) |
| 422 | +{ |
| 423 | + struct pata_fsl_priv *priv = ap->host->private_data; |
| 424 | + |
| 425 | + priv->ultra = adev->dma_mode >= XFER_UDMA_0; |
| 426 | + |
| 427 | + set_ata_bus_timing(adev->dma_mode, to_platform_device(ap->dev)); |
| 428 | +} |
| 429 | +#endif |
| 430 | + |
| 431 | +static int pata_fsl_port_start(struct ata_port *ap) |
| 432 | +{ |
| 433 | + return 0; |
| 434 | +} |
| 435 | + |
| 436 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 437 | + |
| 438 | +static irqreturn_t dma_callback(int channel, void *arg) |
| 439 | +{ |
| 440 | + struct ata_port *ap = arg; |
| 441 | + struct pata_fsl_priv *priv = ap->host->private_data; |
| 442 | + u8 __iomem *ata_regs = priv->fsl_ata_regs; |
| 443 | + |
| 444 | + mcf_edma_stop_transfer(channel); |
| 445 | + priv->dma_done = 1; |
| 446 | + /* |
| 447 | + * DMA is finished, so unmask INTRQ from the drive to allow the |
| 448 | + * normal ISR to fire. |
| 449 | + */ |
| 450 | +#if 0 |
| 451 | + __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN); |
| 452 | +#else |
| 453 | + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN); |
| 454 | + WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL); |
| 455 | +#endif |
| 456 | + |
| 457 | + return IRQ_HANDLED; |
| 458 | +} |
| 459 | + |
| 460 | +static void pata_fsl_bmdma_setup(struct ata_queued_cmd *qc) |
| 461 | +{ |
| 462 | + int chan; |
| 463 | + int dma_ultra; |
| 464 | + u8 ata_control; |
| 465 | + struct ata_port *ap = qc->ap; |
| 466 | + struct pata_fsl_priv *priv = ap->host->private_data; |
| 467 | + u8 __iomem *ata_regs = priv->fsl_ata_regs; |
| 468 | +#if 0 |
| 469 | + struct scatterlist *sg; |
| 470 | + struct fsl_edma_requestbuf *pbuf; |
| 471 | + unsigned int si; |
| 472 | +#endif |
| 473 | + DPRINTK("ENTER\n"); |
| 474 | + |
| 475 | + /* reset the ATA FIFO first */ |
| 476 | + /* |
| 477 | + WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B,FSL_ATA_CONTROL); |
| 478 | + */ |
| 479 | + priv->dma_dir = qc->dma_dir; |
| 480 | + |
| 481 | + /* |
| 482 | + * Configure the on-chip ATA interface hardware. |
| 483 | + */ |
| 484 | + dma_ultra = priv->ultra ? |
| 485 | + FSL_ATA_CTRL_DMA_ULTRA : 0; |
| 486 | + |
| 487 | + ata_control = FSL_ATA_CTRL_FIFO_RST_B | |
| 488 | + FSL_ATA_CTRL_ATA_RST_B | |
| 489 | + FSL_ATA_CTRL_DMA_PENDING | |
| 490 | + dma_ultra; |
| 491 | + |
| 492 | + if (qc->dma_dir == DMA_TO_DEVICE) { |
| 493 | + chan = priv->dma_wchan; |
| 494 | + ata_control |= FSL_ATA_CTRL_FIFO_TX_EN | |
| 495 | + FSL_ATA_CTRL_DMA_WRITE; |
| 496 | + } else { |
| 497 | + chan = priv->dma_rchan; |
| 498 | + ata_control |= FSL_ATA_CTRL_FIFO_RCV_EN; |
| 499 | + } |
| 500 | +#if 0 |
| 501 | + __raw_writel(ata_control, ata_regs + FSL_ATA_CONTROL); |
| 502 | + __raw_writel(plat->fifo_alarm, ata_regs + FSL_ATA_FIFO_ALARM); |
| 503 | + __raw_writel(FSL_ATA_INTR_ATA_INTRQ1, ata_regs + FSL_ATA_INT_EN); |
| 504 | +#else |
| 505 | + WRITE_ATA8(ata_control, FSL_ATA_CONTROL); |
| 506 | + WRITE_ATA8(16/*plat->fifo_alarm*/, FSL_ATA_FIFO_ALARM); |
| 507 | + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ1, FSL_ATA_INT_EN); |
| 508 | +#endif |
| 509 | + /*mb();*/ |
| 510 | + |
| 511 | + /* |
| 512 | + * Set up the DMA completion callback. |
| 513 | + */ |
| 514 | + /* |
| 515 | + * Copy the sg list to an array. |
| 516 | + */ |
| 517 | +#if 0 |
| 518 | + priv->nsg = 0; |
| 519 | + pbuf = priv->reqbuf; |
| 520 | + |
| 521 | + for_each_sg(qc->sg, sg, qc->n_elem, si) { |
| 522 | + |
| 523 | + /*dma_map_sg(NULL, sg, 1, priv->dma_dir); */ |
| 524 | + |
| 525 | + if (priv->dma_dir == DMA_TO_DEVICE) { /* WRITE */ |
| 526 | + pbuf->saddr = sg->dma_address; |
| 527 | + pbuf->daddr = (dma_addr_t)(priv->fsl_ata_regs + 0x18); |
| 528 | + pbuf->soff = 4; |
| 529 | + pbuf->doff = 0; |
| 530 | + } else { /* Read */ |
| 531 | + pbuf->daddr = sg->dma_address; |
| 532 | + pbuf->saddr = (dma_addr_t)(priv->fsl_ata_regs + 0x18); |
| 533 | + pbuf->doff = 4; |
| 534 | + pbuf->soff = 0; |
| 535 | + } |
| 536 | + pbuf->attr = MCF_EDMA_TCD_ATTR_SSIZE_32BIT |
| 537 | + |MCF_EDMA_TCD_ATTR_DSIZE_32BIT; |
| 538 | + pbuf->minor_loop = 16*4; /* 16 longwords per request*/ |
| 539 | + pbuf->len = sg_dma_len(sg); |
| 540 | + |
| 541 | + pbuf++; |
| 542 | + priv->nsg++; |
| 543 | + } |
| 544 | + |
| 545 | + BUG_ON(*(unsigned char *)(ata_regs + FSL_ATA_FIFO_FILL)); |
| 546 | + mcf_edma_sg_config(chan, priv->reqbuf, priv->nsg); |
| 547 | +#else |
| 548 | + if (priv->dma_dir == DMA_TO_DEVICE) { |
| 549 | + mcf_edma_sglist_config(chan, qc->sg, qc->n_elem, priv->dma_dir, |
| 550 | + (dma_addr_t) |
| 551 | + ((io_ata_virt2phys((void *)priv->fsl_ata_regs)) + 0x18), |
| 552 | + MCF_EDMA_TCD_ATTR_SSIZE_32BIT |
| 553 | + | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, |
| 554 | + 4, 0, 8*4); |
| 555 | + } else { |
| 556 | + |
| 557 | + mcf_edma_sglist_config(chan, qc->sg, qc->n_elem, priv->dma_dir, |
| 558 | + (dma_addr_t) |
| 559 | + ((io_ata_virt2phys((void *)priv->fsl_ata_regs)) + 0x18), |
| 560 | + MCF_EDMA_TCD_ATTR_SSIZE_32BIT |
| 561 | + | MCF_EDMA_TCD_ATTR_DSIZE_32BIT, |
| 562 | + 0, 4, 8*4); |
| 563 | + } |
| 564 | + |
| 565 | +#endif |
| 566 | + priv->dma_done = 0; |
| 567 | + |
| 568 | + DPRINTK("EXIT\n"); |
| 569 | + |
| 570 | +} |
| 571 | + |
| 572 | +static void pata_fsl_bmdma_start(struct ata_queued_cmd *qc) |
| 573 | +{ |
| 574 | + struct ata_port *ap = qc->ap; |
| 575 | + struct pata_fsl_priv *priv = ap->host->private_data; |
| 576 | + int chan; |
| 577 | + |
| 578 | + /* |
| 579 | + * Start the channel. |
| 580 | + */ |
| 581 | + chan = qc->dma_dir == DMA_TO_DEVICE ? priv->dma_wchan : priv->dma_rchan; |
| 582 | + |
| 583 | + mcf_edma_enable_transfer(chan); |
| 584 | + |
| 585 | + ap->ops->sff_exec_command(ap, &qc->tf); |
| 586 | +} |
| 587 | + |
| 588 | +static void pata_fsl_bmdma_stop(struct ata_queued_cmd *qc) |
| 589 | +{ |
| 590 | + struct ata_port *ap = qc->ap; |
| 591 | +/* |
| 592 | + int chan; |
| 593 | + |
| 594 | + chan = qc->dma_dir == DMA_TO_DEVICE ? priv->dma_wchan : priv->dma_rchan; |
| 595 | + mcf_edma_stop_transfer(chan); |
| 596 | +*/ |
| 597 | +/* do a dummy read as in ata_bmdma_stop */ |
| 598 | + ata_sff_dma_pause(ap); |
| 599 | +} |
| 600 | + |
| 601 | +static u8 pata_fsl_bmdma_status(struct ata_port *ap) |
| 602 | +{ |
| 603 | + struct pata_fsl_priv *priv = ap->host->private_data; |
| 604 | + |
| 605 | + return priv->dma_done ? ATA_DMA_INTR : 0; |
| 606 | +} |
| 607 | + |
| 608 | +static void pata_fsl_dma_init(struct ata_port *ap) |
| 609 | +{ |
| 610 | + struct pata_fsl_priv *priv = ap->host->private_data; |
| 611 | + |
| 612 | + priv->dma_rchan = -1; |
| 613 | + priv->dma_wchan = -1; |
| 614 | + |
| 615 | + priv->dma_rchan = mcf_edma_request_channel(MCF_EDMA_CHAN_ATA_RX, |
| 616 | + dma_callback, |
| 617 | + NULL, 0x6, |
| 618 | + (void *)ap, |
| 619 | + NULL, |
| 620 | + "MCF ATA RX"); |
| 621 | + if (priv->dma_rchan < 0) { |
| 622 | + dev_printk(KERN_ERR, ap->dev, "couldn't get RX DMA channel\n"); |
| 623 | + goto err_out; |
| 624 | + } |
| 625 | + |
| 626 | + priv->dma_wchan = mcf_edma_request_channel(MCF_EDMA_CHAN_ATA_TX, |
| 627 | + dma_callback, |
| 628 | + NULL, 0x6, |
| 629 | + (void *)ap, |
| 630 | + NULL, |
| 631 | + "MCF ATA TX"); |
| 632 | + if (priv->dma_wchan < 0) { |
| 633 | + dev_printk(KERN_ERR, ap->dev, "couldn't get TX DMA channel\n"); |
| 634 | + goto err_out; |
| 635 | + } |
| 636 | + |
| 637 | + dev_printk(KERN_ERR, ap->dev, "rchan=%d wchan=%d\n", priv->dma_rchan, |
| 638 | + priv->dma_wchan); |
| 639 | + return; |
| 640 | + |
| 641 | +err_out: |
| 642 | + ap->mwdma_mask = 0; |
| 643 | + ap->udma_mask = 0; |
| 644 | + mcf_edma_free_channel(priv->dma_rchan, ap); |
| 645 | + mcf_edma_free_channel(priv->dma_wchan, ap); |
| 646 | + kfree(priv); |
| 647 | +} |
| 648 | +#endif /* CONFIG_FSL_PATA_USE_DMA */ |
| 649 | + |
| 650 | +static void ata_dummy_noret(struct ata_port *ap) { return; } |
| 651 | + |
| 652 | +static struct scsi_host_template pata_fsl_sht = { |
| 653 | + ATA_BMDMA_SHT(DRV_NAME), |
| 654 | + |
| 655 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 656 | + .sg_tablesize = MAX_FSL_SG, |
| 657 | + .dma_boundary = ATA_DMA_BOUNDARY, |
| 658 | +#endif |
| 659 | +}; |
| 660 | + |
| 661 | +static struct ata_port_operations pata_fsl_port_ops = { |
| 662 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 663 | + .inherits = &ata_bmdma_port_ops, |
| 664 | +#else |
| 665 | + .inherits = &ata_sff_port_ops, |
| 666 | +#endif |
| 667 | + .set_piomode = pata_fsl_set_piomode, |
| 668 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 669 | + .set_dmamode = pata_fsl_set_dmamode, |
| 670 | +#endif |
| 671 | + .cable_detect = ata_cable_40wire, |
| 672 | + |
| 673 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 674 | + .bmdma_setup = pata_fsl_bmdma_setup, |
| 675 | + .bmdma_start = pata_fsl_bmdma_start, |
| 676 | +#endif |
| 677 | + |
| 678 | + .sff_data_xfer = ata_sff_data_xfer_noirq, |
| 679 | + .qc_prep = ata_noop_qc_prep, |
| 680 | + |
| 681 | + .port_start = pata_fsl_port_start, |
| 682 | + |
| 683 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 684 | + .bmdma_stop = pata_fsl_bmdma_stop, |
| 685 | + .bmdma_status = pata_fsl_bmdma_status, |
| 686 | +#endif |
| 687 | +}; |
| 688 | + |
| 689 | +static void fsl_setup_port(struct ata_ioports *ioaddr) |
| 690 | +{ |
| 691 | + unsigned int shift = 2; |
| 692 | + |
| 693 | + ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift); |
| 694 | + ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift); |
| 695 | + ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift); |
| 696 | + ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift); |
| 697 | + ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift); |
| 698 | + ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift); |
| 699 | + ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift); |
| 700 | + ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift); |
| 701 | + ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift); |
| 702 | + ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift); |
| 703 | +} |
| 704 | + |
| 705 | +/** |
| 706 | + * pata_fsl_probe - attach a platform interface |
| 707 | + * @pdev: platform device |
| 708 | + * |
| 709 | + * Register a platform bus integrated ATA host controller |
| 710 | + * |
| 711 | + * The 3 platform device resources are used as follows: |
| 712 | + * |
| 713 | + * - I/O Base (IORESOURCE_MEM) virt. addr. of ATA controller regs |
| 714 | + * - CTL Base (IORESOURCE_MEM) unused |
| 715 | + * - IRQ (IORESOURCE_IRQ) platform IRQ assigned to ATA |
| 716 | + * |
| 717 | + */ |
| 718 | +static int __devinit pata_fsl_probe(struct platform_device *pdev) |
| 719 | +{ |
| 720 | + struct resource *io_res; |
| 721 | + struct ata_host *host; |
| 722 | + struct ata_port *ap; |
| 723 | + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) |
| 724 | + pdev->dev.platform_data; |
| 725 | + struct pata_fsl_priv *priv; |
| 726 | + u8 *ata_regs; |
| 727 | + int ret; |
| 728 | + |
| 729 | + DPRINTK("ENTER\n"); |
| 730 | + /* |
| 731 | + * Get an ata_host structure for this device |
| 732 | + */ |
| 733 | + host = ata_host_alloc(&pdev->dev, 1); |
| 734 | + if (!host) |
| 735 | + return -ENOMEM; |
| 736 | + ap = host->ports[0]; |
| 737 | + /* |
| 738 | + * Allocate private data |
| 739 | + */ |
| 740 | + priv = kzalloc(sizeof(struct pata_fsl_priv), GFP_KERNEL); |
| 741 | + if (priv == NULL) { |
| 742 | + /* free(host); */ |
| 743 | + return -ENOMEM; |
| 744 | + } |
| 745 | + host->private_data = priv; |
| 746 | + |
| 747 | + /* |
| 748 | + * Set up resources |
| 749 | + */ |
| 750 | + if (unlikely(pdev->num_resources != 3)) { |
| 751 | + dev_err(&pdev->dev, "invalid number of resources\n"); |
| 752 | + return -EINVAL; |
| 753 | + } |
| 754 | + |
| 755 | + io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 756 | + ata_regs = (u8 *)io_res->start; |
| 757 | + priv->fsl_ata_regs = ata_regs; |
| 758 | + ap->ioaddr.cmd_addr = (void *)(ata_regs + FSL_ATA_DRIVE_DATA); |
| 759 | + ap->ioaddr.ctl_addr = (void *)(ata_regs + FSL_ATA_DRIVE_CONTROL); |
| 760 | + ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; |
| 761 | + ap->ops = &pata_fsl_port_ops; |
| 762 | + ap->pio_mask = 0x3F; |
| 763 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 764 | + ap->mwdma_mask = 0x07; |
| 765 | + ap->udma_mask = 0x1F; |
| 766 | +/* ap->udma_mask = plat->udma_mask; */ |
| 767 | +/* pata_fsl_sht.sg_tablesize = plat->max_sg; */ |
| 768 | +#else |
| 769 | + ap->mwdma_mask = 0x00; |
| 770 | + ap->udma_mask = 0x00; |
| 771 | +#endif |
| 772 | + fsl_setup_port(&ap->ioaddr); |
| 773 | + |
| 774 | + /* |
| 775 | + * Do platform-specific initialization (e.g. allocate pins, |
| 776 | + * turn on clock). After this call it is assumed that |
| 777 | + * plat->get_clk_rate() can be called to calculate |
| 778 | + * timing. |
| 779 | + */ |
| 780 | + if (plat->init && plat->init(pdev)) { |
| 781 | + /* REVISIT: don't leak what ata_host_alloc() allocated */ |
| 782 | + return -ENODEV; |
| 783 | + } |
| 784 | + |
| 785 | + /* Deassert the reset bit to enable the interface */ |
| 786 | + WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL); |
| 787 | + |
| 788 | + /* Set initial timing and mode */ |
| 789 | + set_ata_bus_timing(XFER_PIO_4, pdev); |
| 790 | + |
| 791 | +#ifdef CONFIG_FSL_PATA_USE_DMA |
| 792 | + /* get DMA ready */ |
| 793 | + pata_fsl_dma_init(ap); |
| 794 | +#endif |
| 795 | + |
| 796 | + /* |
| 797 | + * Enable the ATA INTRQ interrupt from the bus, but |
| 798 | + * only allow the CPU to see it (INTRQ2) at this point. |
| 799 | + * INTRQ1, which goes to the DMA, will be enabled later. |
| 800 | + */ |
| 801 | +#if 0 |
| 802 | + __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN); |
| 803 | +#else |
| 804 | + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN); |
| 805 | +#endif |
| 806 | + |
| 807 | + /* activate */ |
| 808 | + ret = ata_host_activate(host, platform_get_irq(pdev, 0), |
| 809 | + ata_sff_interrupt, 0, &pata_fsl_sht); |
| 810 | + DPRINTK("EXIT ret=%d\n", ret); |
| 811 | + return ret; |
| 812 | +} |
| 813 | + |
| 814 | +/** |
| 815 | + * pata_fsl_remove - unplug a platform interface |
| 816 | + * @pdev: platform device |
| 817 | + * |
| 818 | + * A platform bus ATA device has been unplugged. Perform the needed |
| 819 | + * cleanup. Also called on module unload for any active devices. |
| 820 | + */ |
| 821 | +static int __devexit pata_fsl_remove(struct platform_device *pdev) |
| 822 | +{ |
| 823 | + struct device *dev = &pdev->dev; |
| 824 | + struct ata_host *host = dev_get_drvdata(dev); |
| 825 | + struct pata_fsl_priv *priv = host->private_data; |
| 826 | + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) |
| 827 | + pdev->dev.platform_data; |
| 828 | + u8 *ata_regs = priv->fsl_ata_regs; |
| 829 | + |
| 830 | +#if 0 |
| 831 | + __raw_writel(0, ata_regs + FSL_ATA_INT_EN); /* Disable interrupts */ |
| 832 | +#else |
| 833 | + WRITE_ATA8(0, FSL_ATA_INT_EN); /* Disable interrupts */ |
| 834 | +#endif |
| 835 | + |
| 836 | + ata_host_detach(host); |
| 837 | + |
| 838 | + if (plat->exit) |
| 839 | + plat->exit(); |
| 840 | + |
| 841 | + kfree(priv); |
| 842 | + |
| 843 | + return 0; |
| 844 | +} |
| 845 | + |
| 846 | +#ifdef CONFIG_PM |
| 847 | +static int pata_fsl_suspend(struct platform_device *pdev, pm_message_t state) |
| 848 | +{ |
| 849 | + struct ata_host *host = dev_get_drvdata(&pdev->dev); |
| 850 | + struct pata_fsl_priv *priv = host->private_data; |
| 851 | + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) |
| 852 | + pdev->dev.platform_data; |
| 853 | + u8 *ata_regs = priv->fsl_ata_regs; |
| 854 | + |
| 855 | + /* Disable interrupts. */ |
| 856 | +#if 0 |
| 857 | + __raw_writel(0, ata_regs + FSL_ATA_INT_EN); |
| 858 | +#else |
| 859 | + WRITE_ATA8(0, FSL_ATA_INT_EN); |
| 860 | +#endif |
| 861 | + |
| 862 | + if (plat->exit) |
| 863 | + plat->exit(); |
| 864 | + |
| 865 | + return 0; |
| 866 | +} |
| 867 | + |
| 868 | +static int pata_fsl_resume(struct platform_device *pdev) |
| 869 | +{ |
| 870 | + struct ata_host *host = dev_get_drvdata(&pdev->dev); |
| 871 | + struct pata_fsl_priv *priv = host->private_data; |
| 872 | + struct fsl_ata_platform_data *plat = (struct fsl_ata_platform_data *) |
| 873 | + pdev->dev.platform_data; |
| 874 | + u8 *ata_regs = priv->fsl_ata_regs; |
| 875 | + |
| 876 | + if (plat->init && plat->init(pdev)) |
| 877 | + return -ENODEV; |
| 878 | + /* Deassert the reset bit to enable the interface */ |
| 879 | +#if 0 |
| 880 | + __raw_writel(FSL_ATA_CTRL_ATA_RST_B, ata_regs + FSL_ATA_CONTROL); |
| 881 | +#else |
| 882 | + WRITE_ATA8(FSL_ATA_CTRL_ATA_RST_B, FSL_ATA_CONTROL); |
| 883 | +#endif |
| 884 | + |
| 885 | + /* Set initial timing and mode */ |
| 886 | + set_ata_bus_timing(XFER_PIO_4, pdev); |
| 887 | + |
| 888 | + /* |
| 889 | + * Enable hardware interrupts. |
| 890 | + */ |
| 891 | +#if 0 |
| 892 | + __raw_writel(FSL_ATA_INTR_ATA_INTRQ2, ata_regs + FSL_ATA_INT_EN); |
| 893 | +#else |
| 894 | + WRITE_ATA8(FSL_ATA_INTR_ATA_INTRQ2, FSL_ATA_INT_EN); |
| 895 | +#endif |
| 896 | + |
| 897 | + return 0; |
| 898 | +} |
| 899 | +#endif |
| 900 | + |
| 901 | +static struct platform_driver pata_fsl_driver = { |
| 902 | + .probe = pata_fsl_probe, |
| 903 | + .remove = __devexit_p(pata_fsl_remove), |
| 904 | +#ifdef CONFIG_PM |
| 905 | + .suspend = pata_fsl_suspend, |
| 906 | + .resume = pata_fsl_resume, |
| 907 | +#endif |
| 908 | + .driver = { |
| 909 | + .name = DRV_NAME, |
| 910 | + .owner = THIS_MODULE, |
| 911 | + }, |
| 912 | +}; |
| 913 | + |
| 914 | +static int __init pata_fsl_init(void) |
| 915 | +{ |
| 916 | + int ret; |
| 917 | + |
| 918 | + DPRINTK("ENTER\n"); |
| 919 | + ret = platform_driver_register(&pata_fsl_driver); |
| 920 | + DPRINTK("EXIT ret=%d\n", ret); |
| 921 | + return ret; |
| 922 | +} |
| 923 | + |
| 924 | +static void __exit pata_fsl_exit(void) |
| 925 | +{ |
| 926 | + platform_driver_unregister(&pata_fsl_driver); |
| 927 | +} |
| 928 | +module_init(pata_fsl_init); |
| 929 | +module_exit(pata_fsl_exit); |
| 930 | + |
| 931 | +MODULE_AUTHOR("Freescale Semiconductor, Inc."); |
| 932 | +MODULE_DESCRIPTION("low-level driver for Freescale ATA"); |
| 933 | +MODULE_LICENSE("GPL"); |
| 934 | +MODULE_VERSION(DRV_VERSION); |
| 935 | |