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        void __iomem *base;
  21};
  22
  23static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
  24{
  25        struct priv *priv;
  26        phys_addr_t mapbase;
  27        int ret;
  28        int num_cells;
  29        unsigned long flags;
  30
  31        priv = devm_kzalloc(&pdev->dev, sizeof(struct priv), GFP_KERNEL);
  32        if (!priv)
  33                return -ENOMEM;
  34
  35        ret = pci_enable_device(pdev);
  36        if (ret) {
  37                dev_err(&pdev->dev, "Failed to enable PCI device\n");
  38                return -ENODEV;
  39        }
  40
  41        mapbase = pci_resource_start(pdev, 0);
  42        if (!mapbase) {
  43                dev_err(&pdev->dev, "No PCI resource\n");
  44                goto err_start;
  45        }
  46
  47        ret = pci_request_region(pdev, 0, KBUILD_MODNAME);
  48        if (ret) {
  49                dev_err(&pdev->dev, "Failed to request PCI BARs\n");
  50                goto err_start;
  51        }
  52
  53        priv->base = pci_iomap(pdev, 0, 0);
  54        if (!priv->base) {
  55                dev_err(&pdev->dev, "Cannot ioremap\n");
  56                ret = -ENOMEM;
  57                goto err_ioremap;
  58        }
  59
  60        flags = pci_resource_flags(pdev, 0);
  61        if (flags & IORESOURCE_IO) {
  62                ret = -ENOTSUPP;
  63                dev_err(&pdev->dev,
  64                        "IO mapped PCI devices are not supported\n");
  65                goto err_ioremap;
  66        }
  67
  68        pci_set_drvdata(pdev, priv);
  69
  70        priv->bus = mcb_alloc_bus();
  71
  72        ret = chameleon_parse_cells(priv->bus, mapbase, priv->base);
  73        if (ret < 0)
  74                goto err_drvdata;
  75        num_cells = ret;
  76
  77        dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
  78
  79        mcb_bus_add_devices(priv->bus);
  80
  81err_drvdata:
  82        pci_iounmap(pdev, priv->base);
  83err_ioremap:
  84        pci_release_region(pdev, 0);
  85err_start:
  86        pci_disable_device(pdev);
  87        return ret;
  88}
  89
  90static void mcb_pci_remove(struct pci_dev *pdev)
  91{
  92        struct priv *priv = pci_get_drvdata(pdev);
  93
  94        mcb_release_bus(priv->bus);
  95}
  96
  97static const struct pci_device_id mcb_pci_tbl[] = {
  98        { PCI_DEVICE(PCI_VENDOR_ID_MEN, PCI_DEVICE_ID_MEN_CHAMELEON) },
  99        { 0 },
 100};
 101MODULE_DEVICE_TABLE(pci, mcb_pci_tbl);
 102
 103static struct pci_driver mcb_pci_driver = {
 104        .name = "mcb-pci",
 105        .id_table = mcb_pci_tbl,
 106        .probe = mcb_pci_probe,
 107        .remove = mcb_pci_remove,
 108};
 109
 110module_pci_driver(mcb_pci_driver);
 111
 112MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
 113MODULE_LICENSE("GPL");
 114MODULE_DESCRIPTION("MCB over PCI support");
 115