linux/drivers/ata/pata_gayle.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3/*
   4 * Amiga Gayle PATA controller driver
   5 *
   6 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
   7 *              http://www.samsung.com
   8 *
   9 * Based on gayle.c:
  10 *
  11 *     Created 12 Jul 1997 by Geert Uytterhoeven
  12 */
  13
  14#include <linux/ata.h>
  15#include <linux/blkdev.h>
  16#include <linux/delay.h>
  17#include <linux/interrupt.h>
  18#include <linux/kernel.h>
  19#include <linux/libata.h>
  20#include <linux/mm.h>
  21#include <linux/module.h>
  22#include <linux/platform_device.h>
  23#include <linux/zorro.h>
  24#include <scsi/scsi_cmnd.h>
  25#include <scsi/scsi_host.h>
  26
  27#include <asm/amigahw.h>
  28#include <asm/amigaints.h>
  29#include <asm/amigayle.h>
  30#include <asm/ide.h>
  31#include <asm/setup.h>
  32
  33#define DRV_NAME "pata_gayle"
  34#define DRV_VERSION "0.1.0"
  35
  36#define GAYLE_CONTROL   0x101a
  37
  38static struct scsi_host_template pata_gayle_sht = {
  39        ATA_PIO_SHT(DRV_NAME),
  40};
  41
  42/* FIXME: is this needed? */
  43static unsigned int pata_gayle_data_xfer(struct ata_queued_cmd *qc,
  44                                         unsigned char *buf,
  45                                         unsigned int buflen, int rw)
  46{
  47        struct ata_device *dev = qc->dev;
  48        struct ata_port *ap = dev->link->ap;
  49        void __iomem *data_addr = ap->ioaddr.data_addr;
  50        unsigned int words = buflen >> 1;
  51
  52        /* Transfer multiple of 2 bytes */
  53        if (rw == READ)
  54                raw_insw((u16 *)data_addr, (u16 *)buf, words);
  55        else
  56                raw_outsw((u16 *)data_addr, (u16 *)buf, words);
  57
  58        /* Transfer trailing byte, if any. */
  59        if (unlikely(buflen & 0x01)) {
  60                unsigned char pad[2] = { };
  61
  62                /* Point buf to the tail of buffer */
  63                buf += buflen - 1;
  64
  65                if (rw == READ) {
  66                        raw_insw((u16 *)data_addr, (u16 *)pad, 1);
  67                        *buf = pad[0];
  68                } else {
  69                        pad[0] = *buf;
  70                        raw_outsw((u16 *)data_addr, (u16 *)pad, 1);
  71                }
  72                words++;
  73        }
  74
  75        return words << 1;
  76}
  77
  78/*
  79 * Provide our own set_mode() as we don't want to change anything that has
  80 * already been configured..
  81 */
  82static int pata_gayle_set_mode(struct ata_link *link,
  83                               struct ata_device **unused)
  84{
  85        struct ata_device *dev;
  86
  87        ata_for_each_dev(dev, link, ENABLED) {
  88                /* We don't really care */
  89                dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
  90                dev->xfer_shift = ATA_SHIFT_PIO;
  91                dev->flags |= ATA_DFLAG_PIO;
  92                ata_dev_info(dev, "configured for PIO\n");
  93        }
  94        return 0;
  95}
  96
  97static bool pata_gayle_irq_check(struct ata_port *ap)
  98{
  99        u8 ch;
 100
 101        ch = z_readb((unsigned long)ap->private_data);
 102
 103        return !!(ch & GAYLE_IRQ_IDE);
 104}
 105
 106static void pata_gayle_irq_clear(struct ata_port *ap)
 107{
 108        (void)z_readb((unsigned long)ap->ioaddr.status_addr);
 109        z_writeb(0x7c, (unsigned long)ap->private_data);
 110}
 111
 112static struct ata_port_operations pata_gayle_a1200_ops = {
 113        .inherits       = &ata_sff_port_ops,
 114        .sff_data_xfer  = pata_gayle_data_xfer,
 115        .sff_irq_check  = pata_gayle_irq_check,
 116        .sff_irq_clear  = pata_gayle_irq_clear,
 117        .cable_detect   = ata_cable_unknown,
 118        .set_mode       = pata_gayle_set_mode,
 119};
 120
 121static struct ata_port_operations pata_gayle_a4000_ops = {
 122        .inherits       = &ata_sff_port_ops,
 123        .sff_data_xfer  = pata_gayle_data_xfer,
 124        .cable_detect   = ata_cable_unknown,
 125        .set_mode       = pata_gayle_set_mode,
 126};
 127
 128static int __init pata_gayle_init_one(struct platform_device *pdev)
 129{
 130        struct resource *res;
 131        struct gayle_ide_platform_data *pdata;
 132        struct ata_host *host;
 133        struct ata_port *ap;
 134        void __iomem *base;
 135        int ret;
 136
 137        pdata = dev_get_platdata(&pdev->dev);
 138
 139        dev_info(&pdev->dev, "Amiga Gayle IDE controller (A%u style)\n",
 140                pdata->explicit_ack ? 1200 : 4000);
 141
 142        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 143        if (!res)
 144                return -ENODEV;
 145
 146        if (!devm_request_mem_region(&pdev->dev, res->start,
 147                                     resource_size(res), DRV_NAME)) {
 148                pr_err(DRV_NAME ": resources busy\n");
 149                return -EBUSY;
 150        }
 151
 152        /* allocate host */
 153        host = ata_host_alloc(&pdev->dev, 1);
 154        if (!host)
 155                return -ENOMEM;
 156
 157        ap = host->ports[0];
 158
 159        if (pdata->explicit_ack)
 160                ap->ops = &pata_gayle_a1200_ops;
 161        else
 162                ap->ops = &pata_gayle_a4000_ops;
 163
 164        ap->pio_mask = ATA_PIO4;
 165        ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
 166
 167        base = ZTWO_VADDR(pdata->base);
 168        ap->ioaddr.data_addr            = base;
 169        ap->ioaddr.error_addr           = base + 2 + 1 * 4;
 170        ap->ioaddr.feature_addr         = base + 2 + 1 * 4;
 171        ap->ioaddr.nsect_addr           = base + 2 + 2 * 4;
 172        ap->ioaddr.lbal_addr            = base + 2 + 3 * 4;
 173        ap->ioaddr.lbam_addr            = base + 2 + 4 * 4;
 174        ap->ioaddr.lbah_addr            = base + 2 + 5 * 4;
 175        ap->ioaddr.device_addr          = base + 2 + 6 * 4;
 176        ap->ioaddr.status_addr          = base + 2 + 7 * 4;
 177        ap->ioaddr.command_addr         = base + 2 + 7 * 4;
 178
 179        ap->ioaddr.altstatus_addr       = base + GAYLE_CONTROL;
 180        ap->ioaddr.ctl_addr             = base + GAYLE_CONTROL;
 181
 182        ap->private_data = (void *)ZTWO_VADDR(pdata->irqport);
 183
 184        ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", pdata->base,
 185                      pdata->base + GAYLE_CONTROL);
 186
 187        ret = ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt,
 188                                IRQF_SHARED, &pata_gayle_sht);
 189        if (ret)
 190                return ret;
 191
 192        platform_set_drvdata(pdev, host);
 193
 194        return 0;
 195}
 196
 197static int __exit pata_gayle_remove_one(struct platform_device *pdev)
 198{
 199        struct ata_host *host = platform_get_drvdata(pdev);
 200
 201        ata_host_detach(host);
 202
 203        return 0;
 204}
 205
 206static struct platform_driver pata_gayle_driver = {
 207        .remove = __exit_p(pata_gayle_remove_one),
 208        .driver   = {
 209                .name   = "amiga-gayle-ide",
 210        },
 211};
 212
 213module_platform_driver_probe(pata_gayle_driver, pata_gayle_init_one);
 214
 215MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
 216MODULE_DESCRIPTION("low-level driver for Amiga Gayle PATA");
 217MODULE_LICENSE("GPL v2");
 218MODULE_ALIAS("platform:amiga-gayle-ide");
 219MODULE_VERSION(DRV_VERSION);
 220