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