1/* 2 * bdc_pci.c - BRCM BDC USB3.0 device controller PCI interface file. 3 * 4 * Copyright (C) 2014 Broadcom Corporation 5 * 6 * Author: Ashwini Pahuja 7 * 8 * Based on drivers under drivers/usb/ 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 * 15 */ 16 17#include <linux/kernel.h> 18#include <linux/module.h> 19#include <linux/slab.h> 20#include <linux/pci.h> 21#include <linux/pci_ids.h> 22#include <linux/platform_device.h> 23 24#include "bdc.h" 25 26#define BDC_PCI_PID 0x1570 27 28struct bdc_pci { 29 struct device *dev; 30 struct platform_device *bdc; 31}; 32 33static int bdc_setup_msi(struct pci_dev *pci) 34{ 35 int ret; 36 37 ret = pci_enable_msi(pci); 38 if (ret) { 39 pr_err("failed to allocate MSI entry\n"); 40 return ret; 41 } 42 43 return ret; 44} 45 46static int bdc_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) 47{ 48 struct resource res[2]; 49 struct platform_device *bdc; 50 struct bdc_pci *glue; 51 int ret = -ENOMEM; 52 53 glue = devm_kzalloc(&pci->dev, sizeof(*glue), GFP_KERNEL); 54 if (!glue) 55 return -ENOMEM; 56 57 glue->dev = &pci->dev; 58 ret = pci_enable_device(pci); 59 if (ret) { 60 dev_err(&pci->dev, "failed to enable pci device\n"); 61 return -ENODEV; 62 } 63 pci_set_master(pci); 64 65 bdc = platform_device_alloc(BRCM_BDC_NAME, PLATFORM_DEVID_AUTO); 66 if (!bdc) 67 return -ENOMEM; 68 69 memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 70 bdc_setup_msi(pci); 71 72 res[0].start = pci_resource_start(pci, 0); 73 res[0].end = pci_resource_end(pci, 0); 74 res[0].name = BRCM_BDC_NAME; 75 res[0].flags = IORESOURCE_MEM; 76 77 res[1].start = pci->irq; 78 res[1].name = BRCM_BDC_NAME; 79 res[1].flags = IORESOURCE_IRQ; 80 81 ret = platform_device_add_resources(bdc, res, ARRAY_SIZE(res)); 82 if (ret) { 83 dev_err(&pci->dev, 84 "couldn't add resources to bdc device\n"); 85 return ret; 86 } 87 88 pci_set_drvdata(pci, glue); 89 90 dma_set_coherent_mask(&bdc->dev, pci->dev.coherent_dma_mask); 91 92 bdc->dev.dma_mask = pci->dev.dma_mask; 93 bdc->dev.dma_parms = pci->dev.dma_parms; 94 bdc->dev.parent = &pci->dev; 95 glue->bdc = bdc; 96 97 ret = platform_device_add(bdc); 98 if (ret) { 99 dev_err(&pci->dev, "failed to register bdc device\n"); 100 platform_device_put(bdc); 101 return ret; 102 } 103 104 return 0; 105} 106 107static void bdc_pci_remove(struct pci_dev *pci) 108{ 109 struct bdc_pci *glue = pci_get_drvdata(pci); 110 111 platform_device_unregister(glue->bdc); 112 pci_disable_msi(pci); 113} 114 115static struct pci_device_id bdc_pci_id_table[] = { 116 { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, BDC_PCI_PID), }, 117 {} /* Terminating Entry */ 118}; 119 120MODULE_DEVICE_TABLE(pci, bdc_pci_id_table); 121 122static struct pci_driver bdc_pci_driver = { 123 .name = "bdc-pci", 124 .id_table = bdc_pci_id_table, 125 .probe = bdc_pci_probe, 126 .remove = bdc_pci_remove, 127}; 128 129MODULE_AUTHOR("Ashwini Pahuja <ashwini.linux@gmail.com>"); 130MODULE_LICENSE("GPL"); 131MODULE_DESCRIPTION("BRCM BDC USB3 PCI Glue layer"); 132module_pci_driver(bdc_pci_driver); 133