brintos

brintos / linux-shallow public Read only

0
0
Text · 3.5 KiB · 3b634ea Raw
158 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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, table_size;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	flags = pci_resource_flags(pdev, 0);49	if (flags & IORESOURCE_IO) {50		ret = -ENOTSUPP;51		dev_err(&pdev->dev,52			"IO mapped PCI devices are not supported\n");53		goto out_disable;54	}55 56	priv->mapbase = pci_resource_start(pdev, 0);57	if (!priv->mapbase) {58		dev_err(&pdev->dev, "No PCI resource\n");59		ret = -ENODEV;60		goto out_disable;61	}62 63	res = devm_request_mem_region(&pdev->dev, priv->mapbase,64				      CHAM_HEADER_SIZE,65				      KBUILD_MODNAME);66	if (!res) {67		dev_err(&pdev->dev, "Failed to request PCI memory\n");68		ret = -EBUSY;69		goto out_disable;70	}71 72	priv->base = devm_ioremap(&pdev->dev, priv->mapbase, CHAM_HEADER_SIZE);73	if (!priv->base) {74		dev_err(&pdev->dev, "Cannot ioremap\n");75		ret = -ENOMEM;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	table_size = ret;94 95	if (table_size < CHAM_HEADER_SIZE) {96		/* Release the previous resources */97		devm_iounmap(&pdev->dev, priv->base);98		devm_release_mem_region(&pdev->dev, priv->mapbase, CHAM_HEADER_SIZE);99 100		/* Then, allocate it again with the actual chameleon table size */101		res = devm_request_mem_region(&pdev->dev, priv->mapbase,102						table_size,103						KBUILD_MODNAME);104		if (!res) {105			dev_err(&pdev->dev, "Failed to request PCI memory\n");106			ret = -EBUSY;107			goto out_mcb_bus;108		}109 110		priv->base = devm_ioremap(&pdev->dev, priv->mapbase, table_size);111		if (!priv->base) {112			dev_err(&pdev->dev, "Cannot ioremap\n");113			ret = -ENOMEM;114			goto out_mcb_bus;115		}116	}117 118	mcb_bus_add_devices(priv->bus);119 120	return 0;121 122out_mcb_bus:123	mcb_release_bus(priv->bus);124out_disable:125	pci_disable_device(pdev);126	return ret;127}128 129static void mcb_pci_remove(struct pci_dev *pdev)130{131	struct priv *priv = pci_get_drvdata(pdev);132 133	mcb_release_bus(priv->bus);134 135	pci_disable_device(pdev);136}137 138static const struct pci_device_id mcb_pci_tbl[] = {139	{ PCI_DEVICE(PCI_VENDOR_ID_MEN, PCI_DEVICE_ID_MEN_CHAMELEON) },140	{ PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_MEN_CHAMELEON) },141	{ 0 },142};143MODULE_DEVICE_TABLE(pci, mcb_pci_tbl);144 145static struct pci_driver mcb_pci_driver = {146	.name = "mcb-pci",147	.id_table = mcb_pci_tbl,148	.probe = mcb_pci_probe,149	.remove = mcb_pci_remove,150};151 152module_pci_driver(mcb_pci_driver);153 154MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");155MODULE_LICENSE("GPL");156MODULE_DESCRIPTION("MCB over PCI support");157MODULE_IMPORT_NS(MCB);158