linux/drivers/ata/pata_rb532_cf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  A low-level PATA driver to handle a Compact Flash connected on the
   4 *  Mikrotik's RouterBoard 532 board.
   5 *
   6 *  Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
   7 *  Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
   8 *
   9 *  This file was based on: drivers/ata/pata_ixp4xx_cf.c
  10 *      Copyright (C) 2006-07 Tower Technologies
  11 *      Author: Alessandro Zummo <a.zummo@towertech.it>
  12 *
  13 *  Also was based on the driver for Linux 2.4.xx published by Mikrotik for
  14 *  their RouterBoard 1xx and 5xx series devices. The original Mikrotik code
  15 *  seems not to have a license.
  16 */
  17
  18#include <linux/gfp.h>
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/platform_device.h>
  22
  23#include <linux/io.h>
  24#include <linux/interrupt.h>
  25#include <linux/irq.h>
  26#include <linux/gpio/consumer.h>
  27
  28#include <linux/libata.h>
  29#include <scsi/scsi_host.h>
  30
  31#include <asm/mach-rc32434/rb.h>
  32
  33#define DRV_NAME        "pata-rb532-cf"
  34#define DRV_VERSION     "0.1.0"
  35#define DRV_DESC        "PATA driver for RouterBOARD 532 Compact Flash"
  36
  37#define RB500_CF_MAXPORTS       1
  38#define RB500_CF_IO_DELAY       400
  39
  40#define RB500_CF_REG_BASE       0x0800
  41#define RB500_CF_REG_ERR        0x080D
  42#define RB500_CF_REG_CTRL       0x080E
  43/* 32bit buffered data register offset */
  44#define RB500_CF_REG_DBUF32     0x0C00
  45
  46struct rb532_cf_info {
  47        void __iomem    *iobase;
  48        struct gpio_desc *gpio_line;
  49        unsigned int    irq;
  50};
  51
  52/* ------------------------------------------------------------------------ */
  53
  54static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance)
  55{
  56        struct ata_host *ah = dev_instance;
  57        struct rb532_cf_info *info = ah->private_data;
  58
  59        if (gpiod_get_value(info->gpio_line)) {
  60                irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW);
  61                ata_sff_interrupt(info->irq, dev_instance);
  62        } else {
  63                irq_set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
  64        }
  65
  66        return IRQ_HANDLED;
  67}
  68
  69static struct ata_port_operations rb532_pata_port_ops = {
  70        .inherits               = &ata_sff_port_ops,
  71        .sff_data_xfer          = ata_sff_data_xfer32,
  72};
  73
  74/* ------------------------------------------------------------------------ */
  75
  76static struct scsi_host_template rb532_pata_sht = {
  77        ATA_PIO_SHT(DRV_NAME),
  78};
  79
  80/* ------------------------------------------------------------------------ */
  81
  82static void rb532_pata_setup_ports(struct ata_host *ah)
  83{
  84        struct rb532_cf_info *info = ah->private_data;
  85        struct ata_port *ap;
  86
  87        ap = ah->ports[0];
  88
  89        ap->ops         = &rb532_pata_port_ops;
  90        ap->pio_mask    = ATA_PIO4;
  91
  92        ap->ioaddr.cmd_addr     = info->iobase + RB500_CF_REG_BASE;
  93        ap->ioaddr.ctl_addr     = info->iobase + RB500_CF_REG_CTRL;
  94        ap->ioaddr.altstatus_addr = info->iobase + RB500_CF_REG_CTRL;
  95
  96        ata_sff_std_ports(&ap->ioaddr);
  97
  98        ap->ioaddr.data_addr    = info->iobase + RB500_CF_REG_DBUF32;
  99        ap->ioaddr.error_addr   = info->iobase + RB500_CF_REG_ERR;
 100}
 101
 102static int rb532_pata_driver_probe(struct platform_device *pdev)
 103{
 104        int irq;
 105        struct gpio_desc *gpiod;
 106        struct resource *res;
 107        struct ata_host *ah;
 108        struct rb532_cf_info *info;
 109        int ret;
 110
 111        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 112        if (!res) {
 113                dev_err(&pdev->dev, "no IOMEM resource found\n");
 114                return -EINVAL;
 115        }
 116
 117        irq = platform_get_irq(pdev, 0);
 118        if (irq < 0)
 119                return irq;
 120        if (!irq)
 121                return -EINVAL;
 122
 123        gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_IN);
 124        if (IS_ERR(gpiod)) {
 125                dev_err(&pdev->dev, "no GPIO found for irq%d\n", irq);
 126                return PTR_ERR(gpiod);
 127        }
 128        gpiod_set_consumer_name(gpiod, DRV_NAME);
 129
 130        /* allocate host */
 131        ah = ata_host_alloc(&pdev->dev, RB500_CF_MAXPORTS);
 132        if (!ah)
 133                return -ENOMEM;
 134
 135        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 136        if (!info)
 137                return -ENOMEM;
 138
 139        ah->private_data = info;
 140        info->gpio_line = gpiod;
 141        info->irq = irq;
 142
 143        info->iobase = devm_ioremap(&pdev->dev, res->start,
 144                                resource_size(res));
 145        if (!info->iobase)
 146                return -ENOMEM;
 147
 148        rb532_pata_setup_ports(ah);
 149
 150        ret = ata_host_activate(ah, irq, rb532_pata_irq_handler,
 151                                IRQF_TRIGGER_LOW, &rb532_pata_sht);
 152        if (ret)
 153                return ret;
 154
 155        return 0;
 156}
 157
 158static int rb532_pata_driver_remove(struct platform_device *pdev)
 159{
 160        struct ata_host *ah = platform_get_drvdata(pdev);
 161
 162        ata_host_detach(ah);
 163
 164        return 0;
 165}
 166
 167static struct platform_driver rb532_pata_platform_driver = {
 168        .probe          = rb532_pata_driver_probe,
 169        .remove         = rb532_pata_driver_remove,
 170        .driver  = {
 171                .name   = DRV_NAME,
 172        },
 173};
 174
 175#define DRV_INFO DRV_DESC " version " DRV_VERSION
 176
 177module_platform_driver(rb532_pata_platform_driver);
 178
 179MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
 180MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
 181MODULE_DESCRIPTION(DRV_DESC);
 182MODULE_VERSION(DRV_VERSION);
 183MODULE_LICENSE("GPL");
 184MODULE_ALIAS("platform:" DRV_NAME);
 185