Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17-rc2 350 lines 9.2 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * PCI glue driver for SPI PXA2xx compatible controllers. 4 * CE4100's SPI device is more or less the same one as found on PXA. 5 * 6 * Copyright (C) 2016, 2021 Intel Corporation 7 */ 8#include <linux/clk-provider.h> 9#include <linux/device.h> 10#include <linux/err.h> 11#include <linux/module.h> 12#include <linux/pci.h> 13#include <linux/pm.h> 14#include <linux/pm_runtime.h> 15#include <linux/sprintf.h> 16#include <linux/string.h> 17#include <linux/types.h> 18 19#include <linux/dmaengine.h> 20#include <linux/platform_data/dma-dw.h> 21 22#include "spi-pxa2xx.h" 23 24#define PCI_DEVICE_ID_INTEL_QUARK_X1000 0x0935 25#define PCI_DEVICE_ID_INTEL_BYT 0x0f0e 26#define PCI_DEVICE_ID_INTEL_MRFLD 0x1194 27#define PCI_DEVICE_ID_INTEL_BSW0 0x228e 28#define PCI_DEVICE_ID_INTEL_BSW1 0x2290 29#define PCI_DEVICE_ID_INTEL_BSW2 0x22ac 30#define PCI_DEVICE_ID_INTEL_CE4100 0x2e6a 31#define PCI_DEVICE_ID_INTEL_LPT0_0 0x9c65 32#define PCI_DEVICE_ID_INTEL_LPT0_1 0x9c66 33#define PCI_DEVICE_ID_INTEL_LPT1_0 0x9ce5 34#define PCI_DEVICE_ID_INTEL_LPT1_1 0x9ce6 35 36struct pxa_spi_info { 37 int (*setup)(struct pci_dev *pdev, struct pxa2xx_spi_controller *c); 38}; 39 40static struct dw_dma_slave byt_tx_param = { .dst_id = 0 }; 41static struct dw_dma_slave byt_rx_param = { .src_id = 1 }; 42 43static struct dw_dma_slave mrfld3_tx_param = { .dst_id = 15 }; 44static struct dw_dma_slave mrfld3_rx_param = { .src_id = 14 }; 45static struct dw_dma_slave mrfld5_tx_param = { .dst_id = 13 }; 46static struct dw_dma_slave mrfld5_rx_param = { .src_id = 12 }; 47static struct dw_dma_slave mrfld6_tx_param = { .dst_id = 11 }; 48static struct dw_dma_slave mrfld6_rx_param = { .src_id = 10 }; 49 50static struct dw_dma_slave bsw0_tx_param = { .dst_id = 0 }; 51static struct dw_dma_slave bsw0_rx_param = { .src_id = 1 }; 52static struct dw_dma_slave bsw1_tx_param = { .dst_id = 6 }; 53static struct dw_dma_slave bsw1_rx_param = { .src_id = 7 }; 54static struct dw_dma_slave bsw2_tx_param = { .dst_id = 8 }; 55static struct dw_dma_slave bsw2_rx_param = { .src_id = 9 }; 56 57static struct dw_dma_slave lpt1_tx_param = { .dst_id = 0 }; 58static struct dw_dma_slave lpt1_rx_param = { .src_id = 1 }; 59static struct dw_dma_slave lpt0_tx_param = { .dst_id = 2 }; 60static struct dw_dma_slave lpt0_rx_param = { .src_id = 3 }; 61 62static void pxa2xx_spi_pci_clk_unregister(void *clk) 63{ 64 clk_unregister(clk); 65} 66 67static int pxa2xx_spi_pci_clk_register(struct pci_dev *dev, struct ssp_device *ssp, 68 unsigned long rate) 69{ 70 char buf[40]; 71 72 snprintf(buf, sizeof(buf), "pxa2xx-spi.%d", ssp->port_id); 73 ssp->clk = clk_register_fixed_rate(&dev->dev, buf, NULL, 0, rate); 74 if (IS_ERR(ssp->clk)) 75 return PTR_ERR(ssp->clk); 76 77 return devm_add_action_or_reset(&dev->dev, pxa2xx_spi_pci_clk_unregister, ssp->clk); 78} 79 80static bool lpss_dma_filter(struct dma_chan *chan, void *param) 81{ 82 struct dw_dma_slave *dws = param; 83 84 if (dws->dma_dev != chan->device->dev) 85 return false; 86 87 chan->private = dws; 88 return true; 89} 90 91static void lpss_dma_put_device(void *dma_dev) 92{ 93 pci_dev_put(dma_dev); 94} 95 96static int lpss_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) 97{ 98 struct ssp_device *ssp = &c->ssp; 99 struct dw_dma_slave *tx, *rx; 100 struct pci_dev *dma_dev; 101 int ret; 102 103 switch (dev->device) { 104 case PCI_DEVICE_ID_INTEL_BYT: 105 ssp->type = LPSS_BYT_SSP; 106 ssp->port_id = 0; 107 c->tx_param = &byt_tx_param; 108 c->rx_param = &byt_rx_param; 109 break; 110 case PCI_DEVICE_ID_INTEL_BSW0: 111 ssp->type = LPSS_BSW_SSP; 112 ssp->port_id = 0; 113 c->tx_param = &bsw0_tx_param; 114 c->rx_param = &bsw0_rx_param; 115 break; 116 case PCI_DEVICE_ID_INTEL_BSW1: 117 ssp->type = LPSS_BSW_SSP; 118 ssp->port_id = 1; 119 c->tx_param = &bsw1_tx_param; 120 c->rx_param = &bsw1_rx_param; 121 break; 122 case PCI_DEVICE_ID_INTEL_BSW2: 123 ssp->type = LPSS_BSW_SSP; 124 ssp->port_id = 2; 125 c->tx_param = &bsw2_tx_param; 126 c->rx_param = &bsw2_rx_param; 127 break; 128 case PCI_DEVICE_ID_INTEL_LPT0_0: 129 case PCI_DEVICE_ID_INTEL_LPT1_0: 130 ssp->type = LPSS_LPT_SSP; 131 ssp->port_id = 0; 132 c->tx_param = &lpt0_tx_param; 133 c->rx_param = &lpt0_rx_param; 134 break; 135 case PCI_DEVICE_ID_INTEL_LPT0_1: 136 case PCI_DEVICE_ID_INTEL_LPT1_1: 137 ssp->type = LPSS_LPT_SSP; 138 ssp->port_id = 1; 139 c->tx_param = &lpt1_tx_param; 140 c->rx_param = &lpt1_rx_param; 141 break; 142 default: 143 return -ENODEV; 144 } 145 146 c->num_chipselect = 1; 147 148 ret = pxa2xx_spi_pci_clk_register(dev, ssp, 50000000); 149 if (ret) 150 return ret; 151 152 dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); 153 ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); 154 if (ret) 155 return ret; 156 157 tx = c->tx_param; 158 tx->dma_dev = &dma_dev->dev; 159 tx->m_master = 0; 160 tx->p_master = 1; 161 162 rx = c->rx_param; 163 rx->dma_dev = &dma_dev->dev; 164 rx->m_master = 0; 165 rx->p_master = 1; 166 167 c->dma_filter = lpss_dma_filter; 168 c->dma_burst_size = 1; 169 c->enable_dma = 1; 170 return 0; 171} 172 173static const struct pxa_spi_info lpss_info_config = { 174 .setup = lpss_spi_setup, 175}; 176 177static int ce4100_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) 178{ 179 struct ssp_device *ssp = &c->ssp; 180 181 ssp->type = PXA25x_SSP; 182 ssp->port_id = dev->devfn; 183 c->num_chipselect = dev->devfn; 184 185 return pxa2xx_spi_pci_clk_register(dev, ssp, 3686400); 186} 187 188static const struct pxa_spi_info ce4100_info_config = { 189 .setup = ce4100_spi_setup, 190}; 191 192static int mrfld_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) 193{ 194 struct ssp_device *ssp = &c->ssp; 195 struct dw_dma_slave *tx, *rx; 196 struct pci_dev *dma_dev; 197 int ret; 198 199 ssp->type = MRFLD_SSP; 200 201 switch (PCI_FUNC(dev->devfn)) { 202 case 0: 203 ssp->port_id = 3; 204 c->num_chipselect = 1; 205 c->tx_param = &mrfld3_tx_param; 206 c->rx_param = &mrfld3_rx_param; 207 break; 208 case 1: 209 ssp->port_id = 5; 210 c->num_chipselect = 4; 211 c->tx_param = &mrfld5_tx_param; 212 c->rx_param = &mrfld5_rx_param; 213 break; 214 case 2: 215 ssp->port_id = 6; 216 c->num_chipselect = 1; 217 c->tx_param = &mrfld6_tx_param; 218 c->rx_param = &mrfld6_rx_param; 219 break; 220 default: 221 return -ENODEV; 222 } 223 224 ret = pxa2xx_spi_pci_clk_register(dev, ssp, 25000000); 225 if (ret) 226 return ret; 227 228 dma_dev = pci_get_slot(dev->bus, PCI_DEVFN(21, 0)); 229 ret = devm_add_action_or_reset(&dev->dev, lpss_dma_put_device, dma_dev); 230 if (ret) 231 return ret; 232 233 tx = c->tx_param; 234 tx->dma_dev = &dma_dev->dev; 235 236 rx = c->rx_param; 237 rx->dma_dev = &dma_dev->dev; 238 239 c->dma_filter = lpss_dma_filter; 240 c->dma_burst_size = 8; 241 c->enable_dma = 1; 242 return 0; 243} 244 245static const struct pxa_spi_info mrfld_info_config = { 246 .setup = mrfld_spi_setup, 247}; 248 249static int qrk_spi_setup(struct pci_dev *dev, struct pxa2xx_spi_controller *c) 250{ 251 struct ssp_device *ssp = &c->ssp; 252 253 ssp->type = QUARK_X1000_SSP; 254 ssp->port_id = dev->devfn; 255 c->num_chipselect = 1; 256 257 return pxa2xx_spi_pci_clk_register(dev, ssp, 50000000); 258} 259 260static const struct pxa_spi_info qrk_info_config = { 261 .setup = qrk_spi_setup, 262}; 263 264static int pxa2xx_spi_pci_probe(struct pci_dev *dev, 265 const struct pci_device_id *ent) 266{ 267 const struct pxa_spi_info *info; 268 int ret; 269 struct pxa2xx_spi_controller *pdata; 270 struct ssp_device *ssp; 271 272 ret = pcim_enable_device(dev); 273 if (ret) 274 return ret; 275 276 pdata = devm_kzalloc(&dev->dev, sizeof(*pdata), GFP_KERNEL); 277 if (!pdata) 278 return -ENOMEM; 279 280 ssp = &pdata->ssp; 281 ssp->dev = &dev->dev; 282 ssp->phys_base = pci_resource_start(dev, 0); 283 ssp->mmio_base = pcim_iomap_region(dev, 0, "PXA2xx SPI"); 284 if (IS_ERR(ssp->mmio_base)) 285 return PTR_ERR(ssp->mmio_base); 286 287 info = (struct pxa_spi_info *)ent->driver_data; 288 ret = info->setup(dev, pdata); 289 if (ret) 290 return ret; 291 292 pci_set_master(dev); 293 294 ret = pci_alloc_irq_vectors(dev, 1, 1, PCI_IRQ_ALL_TYPES); 295 if (ret < 0) 296 return ret; 297 ssp->irq = pci_irq_vector(dev, 0); 298 299 ret = pxa2xx_spi_probe(&dev->dev, ssp, pdata); 300 if (ret) 301 return ret; 302 303 pm_runtime_set_autosuspend_delay(&dev->dev, 50); 304 pm_runtime_use_autosuspend(&dev->dev); 305 pm_runtime_put_autosuspend(&dev->dev); 306 pm_runtime_allow(&dev->dev); 307 308 return 0; 309} 310 311static void pxa2xx_spi_pci_remove(struct pci_dev *dev) 312{ 313 pm_runtime_forbid(&dev->dev); 314 pm_runtime_get_noresume(&dev->dev); 315 316 pxa2xx_spi_remove(&dev->dev); 317} 318 319static const struct pci_device_id pxa2xx_spi_pci_devices[] = { 320 { PCI_DEVICE_DATA(INTEL, QUARK_X1000, &qrk_info_config) }, 321 { PCI_DEVICE_DATA(INTEL, BYT, &lpss_info_config) }, 322 { PCI_DEVICE_DATA(INTEL, MRFLD, &mrfld_info_config) }, 323 { PCI_DEVICE_DATA(INTEL, BSW0, &lpss_info_config) }, 324 { PCI_DEVICE_DATA(INTEL, BSW1, &lpss_info_config) }, 325 { PCI_DEVICE_DATA(INTEL, BSW2, &lpss_info_config) }, 326 { PCI_DEVICE_DATA(INTEL, CE4100, &ce4100_info_config) }, 327 { PCI_DEVICE_DATA(INTEL, LPT0_0, &lpss_info_config) }, 328 { PCI_DEVICE_DATA(INTEL, LPT0_1, &lpss_info_config) }, 329 { PCI_DEVICE_DATA(INTEL, LPT1_0, &lpss_info_config) }, 330 { PCI_DEVICE_DATA(INTEL, LPT1_1, &lpss_info_config) }, 331 { } 332}; 333MODULE_DEVICE_TABLE(pci, pxa2xx_spi_pci_devices); 334 335static struct pci_driver pxa2xx_spi_pci_driver = { 336 .name = "pxa2xx_spi_pci", 337 .id_table = pxa2xx_spi_pci_devices, 338 .driver = { 339 .pm = pm_ptr(&pxa2xx_spi_pm_ops), 340 }, 341 .probe = pxa2xx_spi_pci_probe, 342 .remove = pxa2xx_spi_pci_remove, 343}; 344 345module_pci_driver(pxa2xx_spi_pci_driver); 346 347MODULE_DESCRIPTION("CE4100/LPSS PCI-SPI glue code for PXA's driver"); 348MODULE_LICENSE("GPL v2"); 349MODULE_IMPORT_NS("SPI_PXA2xx"); 350MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");