linux/drivers/mcb/mcb-pci.c
<<
>>
Prefs
   1/*
   2 * MEN Chameleon Bus.
   3 *
   4 * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
   5 * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published by the Free
   9 * Software Foundation; version 2 of the License.
  10 */
  11
  12#include <linux/module.h>
  13#include <linux/pci.h>
  14#include <linux/mcb.h>
  15
  16#include "mcb-internal.h"
  17
  18struct priv {
  19        struct mcb_bus *bus;
  20        phys_addr_t mapbase;
  21        void __iomem *base;
  22};
  23
  24static int mcb_pci_get_irq(struct mcb_device *mdev)
  25{
  26        struct mcb_bus *mbus = mdev->bus;
  27        struct device *dev = mbus->carrier;
  28        struct pci_dev *pdev = to_pci_dev(dev);
  29
  30        return pdev->irq;
  31}
  32
  33static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
  34{
  35        struct resource *res;
  36        struct priv *priv;
  37        int ret;
  38        int num_cells;
  39        unsigned long flags;
  40
  41        priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL);
  42        if (!priv)
  43                return -ENOMEM;
  44
  45        ret = pci_enable_device(pdev);
  46        if (ret) {
  47                dev_err(&pdev->dev, "Failed to enable PCI device\n");
  48                return -ENODEV;
  49        }
  50
  51        priv->mapbase = pci_resource_start(pdev, 0);
  52        if (!priv->mapbase) {
  53                dev_err(&pdev->dev, "No PCI resource\n");
  54                ret = -ENODEV;
  55                goto out_disable;
  56        }
  57
  58        res = request_mem_region(priv->mapbase, CHAM_HEADER_SIZE,
  59                                 KBUILD_MODNAME);
  60        if (!res) {
  61                dev_err(&pdev->dev, "Failed to request PCI memory\n");
  62                ret = -EBUSY;
  63                goto out_disable;
  64        }
  65
  66        priv->base = ioremap(priv->mapbase, CHAM_HEADER_SIZE);
  67        if (!priv->base) {
  68                dev_err(&pdev->dev, "Cannot ioremap\n");
  69                ret = -ENOMEM;
  70                goto out_release;
  71        }
  72
  73        flags = pci_resource_flags(pdev, 0);
  74        if (flags & IORESOURCE_IO) {
  75                ret = -ENOTSUPP;
  76                dev_err(&pdev->dev,
  77                        "IO mapped PCI devices are not supported\n");
  78                goto out_iounmap;
  79        }
  80
  81        pci_set_drvdata(pdev, priv);
  82
  83        priv->bus = mcb_alloc_bus(&pdev->dev);
  84        if (IS_ERR(priv->bus)) {
  85                ret = PTR_ERR(priv->bus);
  86                goto out_iounmap;
  87        }
  88
  89        priv->bus->get_irq = mcb_pci_get_irq;
  90
  91        ret = chameleon_parse_cells(priv->bus, priv->mapbase, priv->base);
  92        if (ret < 0)
  93                goto out_mcb_bus;
  94        num_cells = ret;
  95
  96        dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
  97
  98        mcb_bus_add_devices(priv->bus);
  99
 100        return 0;
 101
 102out_mcb_bus:
 103        mcb_release_bus(priv->bus);
 104out_iounmap:
 105        iounmap(priv->base);
 106out_release:
 107        pci_release_region(pdev, 0);
 108out_disable:
 109        pci_disable_device(pdev);
 110        return ret;
 111}
 112
 113static void mcb_pci_remove(struct pci_dev *pdev)
 114{
 115        struct priv *priv = pci_get_drvdata(pdev);
 116
 117        mcb_release_bus(priv->bus);
 118
 119        iounmap(priv->base);
 120        release_region(priv->mapbase, CHAM_HEADER_SIZE);
 121        pci_disable_device(pdev);
 122}
 123
 124static const struct pci_device_id mcb_pci_tbl[] = {
 125        { PCI_DEVICE(PCI_VENDOR_ID_MEN, PCI_DEVICE_ID_MEN_CHAMELEON) },
 126        { 0 },
 127};
 128MODULE_DEVICE_TABLE(pci, mcb_pci_tbl);
 129
 130static struct pci_driver mcb_pci_driver = {
 131        .name = "mcb-pci",
 132        .id_table = mcb_pci_tbl,
 133        .probe = mcb_pci_probe,
 134        .remove = mcb_pci_remove,
 135};
 136
 137module_pci_driver(mcb_pci_driver);
 138
 139MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
 140MODULE_LICENSE("GPL");
 141MODULE_DESCRIPTION("MCB over PCI support");
 142