1 /* 2 * PCI interface driver for DW SPI Core 3 * 4 * Copyright (c) 2009, 2014 Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 */ 15 16 #include <linux/interrupt.h> 17 #include <linux/pci.h> 18 #include <linux/slab.h> 19 #include <linux/spi/spi.h> 20 #include <linux/module.h> 21 22 #include "spi-dw.h" 23 24 #define DRIVER_NAME "dw_spi_pci" 25 26 struct dw_spi_pci { 27 struct pci_dev *pdev; 28 struct dw_spi dws; 29 }; 30 31 struct spi_pci_desc { 32 int (*setup)(struct dw_spi *); 33 }; 34 35 static struct spi_pci_desc spi_pci_mid_desc = { 36 .setup = dw_spi_mid_init, 37 }; 38 39 static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 40 { 41 struct dw_spi_pci *dwpci; 42 struct dw_spi *dws; 43 struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data; 44 int pci_bar = 0; 45 int ret; 46 47 ret = pcim_enable_device(pdev); 48 if (ret) 49 return ret; 50 51 dwpci = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_pci), 52 GFP_KERNEL); 53 if (!dwpci) 54 return -ENOMEM; 55 56 dwpci->pdev = pdev; 57 dws = &dwpci->dws; 58 59 /* Get basic io resource and map it */ 60 dws->paddr = pci_resource_start(pdev, pci_bar); 61 62 ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev)); 63 if (ret) 64 return ret; 65 66 dws->regs = pcim_iomap_table(pdev)[pci_bar]; 67 68 dws->bus_num = 0; 69 dws->num_cs = 4; 70 dws->irq = pdev->irq; 71 72 /* 73 * Specific handling for paltforms, like dma setup, 74 * clock rate, FIFO depth. 75 */ 76 if (desc && desc->setup) { 77 ret = desc->setup(dws); 78 if (ret) 79 return ret; 80 } 81 82 ret = dw_spi_add_host(&pdev->dev, dws); 83 if (ret) 84 return ret; 85 86 /* PCI hook and SPI hook use the same drv data */ 87 pci_set_drvdata(pdev, dwpci); 88 89 dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", 90 pdev->vendor, pdev->device); 91 92 return 0; 93 } 94 95 static void spi_pci_remove(struct pci_dev *pdev) 96 { 97 struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); 98 99 dw_spi_remove_host(&dwpci->dws); 100 } 101 102 #ifdef CONFIG_PM_SLEEP 103 static int spi_suspend(struct device *dev) 104 { 105 struct pci_dev *pdev = to_pci_dev(dev); 106 struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); 107 108 return dw_spi_suspend_host(&dwpci->dws); 109 } 110 111 static int spi_resume(struct device *dev) 112 { 113 struct pci_dev *pdev = to_pci_dev(dev); 114 struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); 115 116 return dw_spi_resume_host(&dwpci->dws); 117 } 118 #endif 119 120 static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); 121 122 static const struct pci_device_id pci_ids[] = { 123 /* Intel MID platform SPI controller 0 */ 124 { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc}, 125 {}, 126 }; 127 128 static struct pci_driver dw_spi_driver = { 129 .name = DRIVER_NAME, 130 .id_table = pci_ids, 131 .probe = spi_pci_probe, 132 .remove = spi_pci_remove, 133 .driver = { 134 .pm = &dw_spi_pm_ops, 135 }, 136 }; 137 138 module_pci_driver(dw_spi_driver); 139 140 MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>"); 141 MODULE_DESCRIPTION("PCI interface driver for DW SPI Core"); 142 MODULE_LICENSE("GPL v2"); 143