1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * PCI interface driver for DW SPI Core 4 * 5 * Copyright (c) 2009, 2014 Intel Corporation. 6 */ 7 8 #include <linux/interrupt.h> 9 #include <linux/pci.h> 10 #include <linux/slab.h> 11 #include <linux/spi/spi.h> 12 #include <linux/module.h> 13 14 #include "spi-dw.h" 15 16 #define DRIVER_NAME "dw_spi_pci" 17 18 struct spi_pci_desc { 19 int (*setup)(struct dw_spi *); 20 u16 num_cs; 21 u16 bus_num; 22 }; 23 24 static struct spi_pci_desc spi_pci_mid_desc_1 = { 25 .setup = dw_spi_mid_init, 26 .num_cs = 5, 27 .bus_num = 0, 28 }; 29 30 static struct spi_pci_desc spi_pci_mid_desc_2 = { 31 .setup = dw_spi_mid_init, 32 .num_cs = 2, 33 .bus_num = 1, 34 }; 35 36 static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 37 { 38 struct dw_spi *dws; 39 struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data; 40 int pci_bar = 0; 41 int ret; 42 43 ret = pcim_enable_device(pdev); 44 if (ret) 45 return ret; 46 47 dws = devm_kzalloc(&pdev->dev, sizeof(*dws), GFP_KERNEL); 48 if (!dws) 49 return -ENOMEM; 50 51 /* Get basic io resource and map it */ 52 dws->paddr = pci_resource_start(pdev, pci_bar); 53 54 ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev)); 55 if (ret) 56 return ret; 57 58 dws->regs = pcim_iomap_table(pdev)[pci_bar]; 59 dws->irq = pdev->irq; 60 61 /* 62 * Specific handling for platforms, like dma setup, 63 * clock rate, FIFO depth. 64 */ 65 if (desc) { 66 dws->num_cs = desc->num_cs; 67 dws->bus_num = desc->bus_num; 68 69 if (desc->setup) { 70 ret = desc->setup(dws); 71 if (ret) 72 return ret; 73 } 74 } else { 75 return -ENODEV; 76 } 77 78 ret = dw_spi_add_host(&pdev->dev, dws); 79 if (ret) 80 return ret; 81 82 /* PCI hook and SPI hook use the same drv data */ 83 pci_set_drvdata(pdev, dws); 84 85 dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n", 86 pdev->vendor, pdev->device); 87 88 return 0; 89 } 90 91 static void spi_pci_remove(struct pci_dev *pdev) 92 { 93 struct dw_spi *dws = pci_get_drvdata(pdev); 94 95 dw_spi_remove_host(dws); 96 } 97 98 #ifdef CONFIG_PM_SLEEP 99 static int spi_suspend(struct device *dev) 100 { 101 struct pci_dev *pdev = to_pci_dev(dev); 102 struct dw_spi *dws = pci_get_drvdata(pdev); 103 104 return dw_spi_suspend_host(dws); 105 } 106 107 static int spi_resume(struct device *dev) 108 { 109 struct pci_dev *pdev = to_pci_dev(dev); 110 struct dw_spi *dws = pci_get_drvdata(pdev); 111 112 return dw_spi_resume_host(dws); 113 } 114 #endif 115 116 static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume); 117 118 static const struct pci_device_id pci_ids[] = { 119 /* Intel MID platform SPI controller 0 */ 120 /* 121 * The access to the device 8086:0801 is disabled by HW, since it's 122 * exclusively used by SCU to communicate with MSIC. 123 */ 124 /* Intel MID platform SPI controller 1 */ 125 { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1}, 126 /* Intel MID platform SPI controller 2 */ 127 { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2}, 128 {}, 129 }; 130 131 static struct pci_driver dw_spi_driver = { 132 .name = DRIVER_NAME, 133 .id_table = pci_ids, 134 .probe = spi_pci_probe, 135 .remove = spi_pci_remove, 136 .driver = { 137 .pm = &dw_spi_pm_ops, 138 }, 139 }; 140 141 module_pci_driver(dw_spi_driver); 142 143 MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>"); 144 MODULE_DESCRIPTION("PCI interface driver for DW SPI Core"); 145 MODULE_LICENSE("GPL v2"); 146