linux/drivers/ide/au1xxx-ide.c
<<
>>
Prefs
   1/*
   2 * BRIEF MODULE DESCRIPTION
   3 * AMD Alchemy Au1xxx IDE interface routines over the Static Bus
   4 *
   5 * Copyright (c) 2003-2005 AMD, Personal Connectivity Solutions
   6 *
   7 * This program is free software; you can redistribute it and/or modify it under
   8 * the terms of the GNU General Public License as published by the Free Software
   9 * Foundation; either version 2 of the License, or (at your option) any later
  10 * version.
  11 *
  12 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  13 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
  14 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
  15 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  16 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  17 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  18 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  19 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  20 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  21 * POSSIBILITY OF SUCH DAMAGE.
  22 *
  23 * You should have received a copy of the GNU General Public License along with
  24 * this program; if not, write to the Free Software Foundation, Inc.,
  25 * 675 Mass Ave, Cambridge, MA 02139, USA.
  26 *
  27 * Note: for more information, please refer "AMD Alchemy Au1200/Au1550 IDE
  28 *       Interface and Linux Device Driver" Application Note.
  29 */
  30#include <linux/types.h>
  31#include <linux/module.h>
  32#include <linux/kernel.h>
  33#include <linux/delay.h>
  34#include <linux/platform_device.h>
  35#include <linux/init.h>
  36#include <linux/ide.h>
  37#include <linux/scatterlist.h>
  38
  39#include <asm/mach-au1x00/au1000.h>
  40#include <asm/mach-au1x00/au1xxx_dbdma.h>
  41#include <asm/mach-au1x00/au1xxx_ide.h>
  42
  43#define DRV_NAME        "au1200-ide"
  44#define DRV_AUTHOR      "Enrico Walther <enrico.walther@amd.com> / Pete Popov <ppopov@embeddedalley.com>"
  45
  46#ifndef IDE_REG_SHIFT
  47#define IDE_REG_SHIFT 5
  48#endif
  49
  50/* enable the burstmode in the dbdma */
  51#define IDE_AU1XXX_BURSTMODE    1
  52
  53static _auide_hwif auide_hwif;
  54
  55#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
  56
  57static inline void auide_insw(unsigned long port, void *addr, u32 count)
  58{
  59        _auide_hwif *ahwif = &auide_hwif;
  60        chan_tab_t *ctp;
  61        au1x_ddma_desc_t *dp;
  62
  63        if (!au1xxx_dbdma_put_dest(ahwif->rx_chan, virt_to_phys(addr),
  64                                   count << 1, DDMA_FLAGS_NOIE)) {
  65                printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
  66                return;
  67        }
  68        ctp = *((chan_tab_t **)ahwif->rx_chan);
  69        dp = ctp->cur_ptr;
  70        while (dp->dscr_cmd0 & DSCR_CMD0_V)
  71                ;
  72        ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
  73}
  74
  75static inline void auide_outsw(unsigned long port, void *addr, u32 count)
  76{
  77        _auide_hwif *ahwif = &auide_hwif;
  78        chan_tab_t *ctp;
  79        au1x_ddma_desc_t *dp;
  80
  81        if (!au1xxx_dbdma_put_source(ahwif->tx_chan, virt_to_phys(addr),
  82                                     count << 1, DDMA_FLAGS_NOIE)) {
  83                printk(KERN_ERR "%s failed %d\n", __func__, __LINE__);
  84                return;
  85        }
  86        ctp = *((chan_tab_t **)ahwif->tx_chan);
  87        dp = ctp->cur_ptr;
  88        while (dp->dscr_cmd0 & DSCR_CMD0_V)
  89                ;
  90        ctp->cur_ptr = au1xxx_ddma_get_nextptr_virt(dp);
  91}
  92
  93static void au1xxx_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
  94                              void *buf, unsigned int len)
  95{
  96        auide_insw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
  97}
  98
  99static void au1xxx_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
 100                               void *buf, unsigned int len)
 101{
 102        auide_outsw(drive->hwif->io_ports.data_addr, buf, (len + 1) / 2);
 103}
 104#endif
 105
 106static void au1xxx_set_pio_mode(ide_hwif_t *hwif, ide_drive_t *drive)
 107{
 108        int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
 109
 110        switch (drive->pio_mode - XFER_PIO_0) {
 111        case 0:
 112                mem_sttime = SBC_IDE_TIMING(PIO0);
 113
 114                /* set configuration for RCS2# */
 115                mem_stcfg |= TS_MASK;
 116                mem_stcfg &= ~TCSOE_MASK;
 117                mem_stcfg &= ~TOECS_MASK;
 118                mem_stcfg |= SBC_IDE_PIO0_TCSOE | SBC_IDE_PIO0_TOECS;
 119                break;
 120
 121        case 1:
 122                mem_sttime = SBC_IDE_TIMING(PIO1);
 123
 124                /* set configuration for RCS2# */
 125                mem_stcfg |= TS_MASK;
 126                mem_stcfg &= ~TCSOE_MASK;
 127                mem_stcfg &= ~TOECS_MASK;
 128                mem_stcfg |= SBC_IDE_PIO1_TCSOE | SBC_IDE_PIO1_TOECS;
 129                break;
 130
 131        case 2:
 132                mem_sttime = SBC_IDE_TIMING(PIO2);
 133
 134                /* set configuration for RCS2# */
 135                mem_stcfg &= ~TS_MASK;
 136                mem_stcfg &= ~TCSOE_MASK;
 137                mem_stcfg &= ~TOECS_MASK;
 138                mem_stcfg |= SBC_IDE_PIO2_TCSOE | SBC_IDE_PIO2_TOECS;
 139                break;
 140
 141        case 3:
 142                mem_sttime = SBC_IDE_TIMING(PIO3);
 143
 144                /* set configuration for RCS2# */
 145                mem_stcfg &= ~TS_MASK;
 146                mem_stcfg &= ~TCSOE_MASK;
 147                mem_stcfg &= ~TOECS_MASK;
 148                mem_stcfg |= SBC_IDE_PIO3_TCSOE | SBC_IDE_PIO3_TOECS;
 149
 150                break;
 151
 152        case 4:
 153                mem_sttime = SBC_IDE_TIMING(PIO4);
 154
 155                /* set configuration for RCS2# */
 156                mem_stcfg &= ~TS_MASK;
 157                mem_stcfg &= ~TCSOE_MASK;
 158                mem_stcfg &= ~TOECS_MASK;
 159                mem_stcfg |= SBC_IDE_PIO4_TCSOE | SBC_IDE_PIO4_TOECS;
 160                break;
 161        }
 162
 163        au_writel(mem_sttime,MEM_STTIME2);
 164        au_writel(mem_stcfg,MEM_STCFG2);
 165}
 166
 167static void auide_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive)
 168{
 169        int mem_sttime = 0, mem_stcfg = au_readl(MEM_STCFG2);
 170
 171        switch (drive->dma_mode) {
 172#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 173        case XFER_MW_DMA_2:
 174                mem_sttime = SBC_IDE_TIMING(MDMA2);
 175
 176                /* set configuration for RCS2# */
 177                mem_stcfg &= ~TS_MASK;
 178                mem_stcfg &= ~TCSOE_MASK;
 179                mem_stcfg &= ~TOECS_MASK;
 180                mem_stcfg |= SBC_IDE_MDMA2_TCSOE | SBC_IDE_MDMA2_TOECS;
 181
 182                break;
 183        case XFER_MW_DMA_1:
 184                mem_sttime = SBC_IDE_TIMING(MDMA1);
 185
 186                /* set configuration for RCS2# */
 187                mem_stcfg &= ~TS_MASK;
 188                mem_stcfg &= ~TCSOE_MASK;
 189                mem_stcfg &= ~TOECS_MASK;
 190                mem_stcfg |= SBC_IDE_MDMA1_TCSOE | SBC_IDE_MDMA1_TOECS;
 191
 192                break;
 193        case XFER_MW_DMA_0:
 194                mem_sttime = SBC_IDE_TIMING(MDMA0);
 195
 196                /* set configuration for RCS2# */
 197                mem_stcfg |= TS_MASK;
 198                mem_stcfg &= ~TCSOE_MASK;
 199                mem_stcfg &= ~TOECS_MASK;
 200                mem_stcfg |= SBC_IDE_MDMA0_TCSOE | SBC_IDE_MDMA0_TOECS;
 201
 202                break;
 203#endif
 204        }
 205
 206        au_writel(mem_sttime,MEM_STTIME2);
 207        au_writel(mem_stcfg,MEM_STCFG2);
 208}
 209
 210/*
 211 * Multi-Word DMA + DbDMA functions
 212 */
 213
 214#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 215static int auide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
 216{
 217        ide_hwif_t *hwif = drive->hwif;
 218        _auide_hwif *ahwif = &auide_hwif;
 219        struct scatterlist *sg;
 220        int i = cmd->sg_nents, count = 0;
 221        int iswrite = !!(cmd->tf_flags & IDE_TFLAG_WRITE);
 222
 223        /* Save for interrupt context */
 224        ahwif->drive = drive;
 225
 226        /* fill the descriptors */
 227        sg = hwif->sg_table;
 228        while (i && sg_dma_len(sg)) {
 229                u32 cur_addr;
 230                u32 cur_len;
 231
 232                cur_addr = sg_dma_address(sg);
 233                cur_len = sg_dma_len(sg);
 234
 235                while (cur_len) {
 236                        u32 flags = DDMA_FLAGS_NOIE;
 237                        unsigned int tc = (cur_len < 0xfe00)? cur_len: 0xfe00;
 238
 239                        if (++count >= PRD_ENTRIES) {
 240                                printk(KERN_WARNING "%s: DMA table too small\n",
 241                                       drive->name);
 242                                return 0;
 243                        }
 244
 245                        /* Lets enable intr for the last descriptor only */
 246                        if (1==i)
 247                                flags = DDMA_FLAGS_IE;
 248                        else
 249                                flags = DDMA_FLAGS_NOIE;
 250
 251                        if (iswrite) {
 252                                if (!au1xxx_dbdma_put_source(ahwif->tx_chan,
 253                                        sg_phys(sg), tc, flags)) {
 254                                        printk(KERN_ERR "%s failed %d\n", 
 255                                               __func__, __LINE__);
 256                                }
 257                        } else  {
 258                                if (!au1xxx_dbdma_put_dest(ahwif->rx_chan,
 259                                        sg_phys(sg), tc, flags)) {
 260                                        printk(KERN_ERR "%s failed %d\n", 
 261                                               __func__, __LINE__);
 262                                }
 263                        }
 264
 265                        cur_addr += tc;
 266                        cur_len -= tc;
 267                }
 268                sg = sg_next(sg);
 269                i--;
 270        }
 271
 272        if (count)
 273                return 1;
 274
 275        return 0; /* revert to PIO for this request */
 276}
 277
 278static int auide_dma_end(ide_drive_t *drive)
 279{
 280        return 0;
 281}
 282
 283static void auide_dma_start(ide_drive_t *drive )
 284{
 285}
 286
 287
 288static int auide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
 289{
 290        if (auide_build_dmatable(drive, cmd) == 0)
 291                return 1;
 292
 293        return 0;
 294}
 295
 296static int auide_dma_test_irq(ide_drive_t *drive)
 297{
 298        /* If dbdma didn't execute the STOP command yet, the
 299         * active bit is still set
 300         */
 301        drive->waiting_for_dma++;
 302        if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) {
 303                printk(KERN_WARNING "%s: timeout waiting for ddma to complete\n",
 304                       drive->name);
 305                return 1;
 306        }
 307        udelay(10);
 308        return 0;
 309}
 310
 311static void auide_dma_host_set(ide_drive_t *drive, int on)
 312{
 313}
 314
 315static void auide_ddma_tx_callback(int irq, void *param)
 316{
 317}
 318
 319static void auide_ddma_rx_callback(int irq, void *param)
 320{
 321}
 322#endif /* end CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA */
 323
 324static void auide_init_dbdma_dev(dbdev_tab_t *dev, u32 dev_id, u32 tsize,
 325                                 u32 devwidth, u32 flags, u32 regbase)
 326{
 327        dev->dev_id          = dev_id;
 328        dev->dev_physaddr    = CPHYSADDR(regbase);
 329        dev->dev_intlevel    = 0;
 330        dev->dev_intpolarity = 0;
 331        dev->dev_tsize       = tsize;
 332        dev->dev_devwidth    = devwidth;
 333        dev->dev_flags       = flags;
 334}
 335
 336#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 337static const struct ide_dma_ops au1xxx_dma_ops = {
 338        .dma_host_set           = auide_dma_host_set,
 339        .dma_setup              = auide_dma_setup,
 340        .dma_start              = auide_dma_start,
 341        .dma_end                = auide_dma_end,
 342        .dma_test_irq           = auide_dma_test_irq,
 343        .dma_lost_irq           = ide_dma_lost_irq,
 344};
 345
 346static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
 347{
 348        _auide_hwif *auide = &auide_hwif;
 349        dbdev_tab_t source_dev_tab, target_dev_tab;
 350        u32 dev_id, tsize, devwidth, flags;
 351
 352        dev_id   = hwif->ddma_id;
 353
 354        tsize    =  8; /*  1 */
 355        devwidth = 32; /* 16 */
 356
 357#ifdef IDE_AU1XXX_BURSTMODE 
 358        flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
 359#else
 360        flags = DEV_FLAGS_SYNC;
 361#endif
 362
 363        /* setup dev_tab for tx channel */
 364        auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth,
 365                             DEV_FLAGS_OUT | flags, auide->regbase);
 366        auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
 367
 368        auide_init_dbdma_dev(&source_dev_tab, dev_id, tsize, devwidth,
 369                             DEV_FLAGS_IN | flags, auide->regbase);
 370        auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
 371        
 372        /* We also need to add a target device for the DMA */
 373        auide_init_dbdma_dev(&target_dev_tab, (u32)DSCR_CMD0_ALWAYS, tsize,
 374                             devwidth, DEV_FLAGS_ANYUSE, auide->regbase);
 375        auide->target_dev_id = au1xxx_ddma_add_device(&target_dev_tab); 
 376 
 377        /* Get a channel for TX */
 378        auide->tx_chan = au1xxx_dbdma_chan_alloc(auide->target_dev_id,
 379                                                 auide->tx_dev_id,
 380                                                 auide_ddma_tx_callback,
 381                                                 (void*)auide);
 382 
 383        /* Get a channel for RX */
 384        auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
 385                                                 auide->target_dev_id,
 386                                                 auide_ddma_rx_callback,
 387                                                 (void*)auide);
 388
 389        auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
 390                                                             NUM_DESCRIPTORS);
 391        auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
 392                                                             NUM_DESCRIPTORS);
 393
 394        /* FIXME: check return value */
 395        (void)ide_allocate_dma_engine(hwif);
 396        
 397        au1xxx_dbdma_start( auide->tx_chan );
 398        au1xxx_dbdma_start( auide->rx_chan );
 399 
 400        return 0;
 401} 
 402#else
 403static int auide_ddma_init(ide_hwif_t *hwif, const struct ide_port_info *d)
 404{
 405        _auide_hwif *auide = &auide_hwif;
 406        dbdev_tab_t source_dev_tab;
 407        int flags;
 408
 409#ifdef IDE_AU1XXX_BURSTMODE 
 410        flags = DEV_FLAGS_SYNC | DEV_FLAGS_BURSTABLE;
 411#else
 412        flags = DEV_FLAGS_SYNC;
 413#endif
 414
 415        /* setup dev_tab for tx channel */
 416        auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32,
 417                             DEV_FLAGS_OUT | flags, auide->regbase);
 418        auide->tx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
 419
 420        auide_init_dbdma_dev(&source_dev_tab, (u32)DSCR_CMD0_ALWAYS, 8, 32,
 421                             DEV_FLAGS_IN | flags, auide->regbase);
 422        auide->rx_dev_id = au1xxx_ddma_add_device( &source_dev_tab );
 423        
 424        /* Get a channel for TX */
 425        auide->tx_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
 426                                                 auide->tx_dev_id,
 427                                                 NULL,
 428                                                 (void*)auide);
 429 
 430        /* Get a channel for RX */
 431        auide->rx_chan = au1xxx_dbdma_chan_alloc(auide->rx_dev_id,
 432                                                 DSCR_CMD0_ALWAYS,
 433                                                 NULL,
 434                                                 (void*)auide);
 435 
 436        auide->tx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->tx_chan,
 437                                                             NUM_DESCRIPTORS);
 438        auide->rx_desc_head = (void*)au1xxx_dbdma_ring_alloc(auide->rx_chan,
 439                                                             NUM_DESCRIPTORS);
 440 
 441        au1xxx_dbdma_start( auide->tx_chan );
 442        au1xxx_dbdma_start( auide->rx_chan );
 443        
 444        return 0;
 445}
 446#endif
 447
 448static void auide_setup_ports(struct ide_hw *hw, _auide_hwif *ahwif)
 449{
 450        int i;
 451        unsigned long *ata_regs = hw->io_ports_array;
 452
 453        /* FIXME? */
 454        for (i = 0; i < 8; i++)
 455                *ata_regs++ = ahwif->regbase + (i << IDE_REG_SHIFT);
 456
 457        /* set the Alternative Status register */
 458        *ata_regs = ahwif->regbase + (14 << IDE_REG_SHIFT);
 459}
 460
 461#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
 462static const struct ide_tp_ops au1xxx_tp_ops = {
 463        .exec_command           = ide_exec_command,
 464        .read_status            = ide_read_status,
 465        .read_altstatus         = ide_read_altstatus,
 466        .write_devctl           = ide_write_devctl,
 467
 468        .dev_select             = ide_dev_select,
 469        .tf_load                = ide_tf_load,
 470        .tf_read                = ide_tf_read,
 471
 472        .input_data             = au1xxx_input_data,
 473        .output_data            = au1xxx_output_data,
 474};
 475#endif
 476
 477static const struct ide_port_ops au1xxx_port_ops = {
 478        .set_pio_mode           = au1xxx_set_pio_mode,
 479        .set_dma_mode           = auide_set_dma_mode,
 480};
 481
 482static const struct ide_port_info au1xxx_port_info = {
 483        .init_dma               = auide_ddma_init,
 484#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
 485        .tp_ops                 = &au1xxx_tp_ops,
 486#endif
 487        .port_ops               = &au1xxx_port_ops,
 488#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 489        .dma_ops                = &au1xxx_dma_ops,
 490#endif
 491        .host_flags             = IDE_HFLAG_POST_SET_MODE |
 492                                  IDE_HFLAG_NO_IO_32BIT |
 493                                  IDE_HFLAG_UNMASK_IRQS,
 494        .pio_mask               = ATA_PIO4,
 495#ifdef CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
 496        .mwdma_mask             = ATA_MWDMA2,
 497#endif
 498        .chipset                = ide_au1xxx,
 499};
 500
 501static int au_ide_probe(struct platform_device *dev)
 502{
 503        _auide_hwif *ahwif = &auide_hwif;
 504        struct resource *res;
 505        struct ide_host *host;
 506        int ret = 0;
 507        struct ide_hw hw, *hws[] = { &hw };
 508
 509#if defined(CONFIG_BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA)
 510        char *mode = "MWDMA2";
 511#elif defined(CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA)
 512        char *mode = "PIO+DDMA(offload)";
 513#endif
 514
 515        memset(&auide_hwif, 0, sizeof(_auide_hwif));
 516        ahwif->irq = platform_get_irq(dev, 0);
 517
 518        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 519
 520        if (res == NULL) {
 521                pr_debug("%s %d: no base address\n", DRV_NAME, dev->id);
 522                ret = -ENODEV;
 523                goto out;
 524        }
 525        if (ahwif->irq < 0) {
 526                pr_debug("%s %d: no IRQ\n", DRV_NAME, dev->id);
 527                ret = -ENODEV;
 528                goto out;
 529        }
 530
 531        if (!request_mem_region(res->start, resource_size(res), dev->name)) {
 532                pr_debug("%s: request_mem_region failed\n", DRV_NAME);
 533                ret =  -EBUSY;
 534                goto out;
 535        }
 536
 537        ahwif->regbase = (u32)ioremap(res->start, resource_size(res));
 538        if (ahwif->regbase == 0) {
 539                ret = -ENOMEM;
 540                goto out;
 541        }
 542
 543        res = platform_get_resource(dev, IORESOURCE_DMA, 0);
 544        if (!res) {
 545                pr_debug("%s: no DDMA ID resource\n", DRV_NAME);
 546                ret = -ENODEV;
 547                goto out;
 548        }
 549        ahwif->ddma_id = res->start;
 550
 551        memset(&hw, 0, sizeof(hw));
 552        auide_setup_ports(&hw, ahwif);
 553        hw.irq = ahwif->irq;
 554        hw.dev = &dev->dev;
 555
 556        ret = ide_host_add(&au1xxx_port_info, hws, 1, &host);
 557        if (ret)
 558                goto out;
 559
 560        auide_hwif.hwif = host->ports[0];
 561
 562        platform_set_drvdata(dev, host);
 563
 564        printk(KERN_INFO "Au1xxx IDE(builtin) configured for %s\n", mode );
 565
 566 out:
 567        return ret;
 568}
 569
 570static int au_ide_remove(struct platform_device *dev)
 571{
 572        struct resource *res;
 573        struct ide_host *host = platform_get_drvdata(dev);
 574        _auide_hwif *ahwif = &auide_hwif;
 575
 576        ide_host_remove(host);
 577
 578        iounmap((void *)ahwif->regbase);
 579
 580        res = platform_get_resource(dev, IORESOURCE_MEM, 0);
 581        release_mem_region(res->start, resource_size(res));
 582
 583        return 0;
 584}
 585
 586static struct platform_driver au1200_ide_driver = {
 587        .driver = {
 588                .name           = "au1200-ide",
 589        },
 590        .probe          = au_ide_probe,
 591        .remove         = au_ide_remove,
 592};
 593
 594module_platform_driver(au1200_ide_driver);
 595
 596MODULE_LICENSE("GPL");
 597MODULE_DESCRIPTION("AU1200 IDE driver");
 598