^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * PCI interface driver for DW SPI Core
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) 2009, 2014 Intel Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/pm_runtime.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/spi/spi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "spi-dw.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define DRIVER_NAME "dw_spi_pci"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /* HW info for MRST Clk Control Unit, 32b reg per controller */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #define MRST_SPI_CLK_BASE 100000000 /* 100m */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define MRST_CLK_SPI_REG 0xff11d86c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define CLK_SPI_BDIV_OFFSET 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define CLK_SPI_BDIV_MASK 0x00000007
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define CLK_SPI_CDIV_OFFSET 9
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define CLK_SPI_CDIV_MASK 0x00000e00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define CLK_SPI_DISABLE_OFFSET 8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct spi_pci_desc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int (*setup)(struct dw_spi *);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u16 num_cs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) u16 bus_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u32 max_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static int spi_mid_init(struct dw_spi *dws)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) void __iomem *clk_reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) u32 clk_cdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) clk_reg = ioremap(MRST_CLK_SPI_REG, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) if (!clk_reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* Get SPI controller operating freq info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) clk_cdiv = readl(clk_reg + dws->bus_num * sizeof(u32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) clk_cdiv &= CLK_SPI_CDIV_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) clk_cdiv >>= CLK_SPI_CDIV_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) iounmap(clk_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) dw_spi_dma_setup_mfld(dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) static int spi_generic_init(struct dw_spi *dws)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) dw_spi_dma_setup_generic(dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) static struct spi_pci_desc spi_pci_mid_desc_1 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) .setup = spi_mid_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) .num_cs = 5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) .bus_num = 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static struct spi_pci_desc spi_pci_mid_desc_2 = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) .setup = spi_mid_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) .num_cs = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) .bus_num = 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) static struct spi_pci_desc spi_pci_ehl_desc = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) .setup = spi_generic_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) .num_cs = 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) .bus_num = -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) .max_freq = 100000000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct dw_spi *dws;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct spi_pci_desc *desc = (struct spi_pci_desc *)ent->driver_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) int pci_bar = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) ret = pcim_enable_device(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) dws = devm_kzalloc(&pdev->dev, sizeof(*dws), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!dws)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) /* Get basic io resource and map it */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) dws->paddr = pci_resource_start(pdev, pci_bar);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) pci_set_master(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) ret = pcim_iomap_regions(pdev, 1 << pci_bar, pci_name(pdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) dws->regs = pcim_iomap_table(pdev)[pci_bar];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) dws->irq = pci_irq_vector(pdev, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) * Specific handling for platforms, like dma setup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * clock rate, FIFO depth.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) if (desc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) dws->num_cs = desc->num_cs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) dws->bus_num = desc->bus_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) dws->max_freq = desc->max_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (desc->setup) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) ret = desc->setup(dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) goto err_free_irq_vectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ret = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) goto err_free_irq_vectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) ret = dw_spi_add_host(&pdev->dev, dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) goto err_free_irq_vectors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) /* PCI hook and SPI hook use the same drv data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) pci_set_drvdata(pdev, dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) dev_info(&pdev->dev, "found PCI SPI controller(ID: %04x:%04x)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pdev->vendor, pdev->device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) pm_runtime_use_autosuspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) pm_runtime_put_autosuspend(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) pm_runtime_allow(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) err_free_irq_vectors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) pci_free_irq_vectors(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static void spi_pci_remove(struct pci_dev *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct dw_spi *dws = pci_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) pm_runtime_forbid(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) pm_runtime_get_noresume(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) dw_spi_remove_host(dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) pci_free_irq_vectors(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) static int spi_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) struct dw_spi *dws = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return dw_spi_suspend_host(dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) static int spi_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct dw_spi *dws = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return dw_spi_resume_host(dws);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static const struct pci_device_id pci_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) /* Intel MID platform SPI controller 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) * The access to the device 8086:0801 is disabled by HW, since it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * exclusively used by SCU to communicate with MSIC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) /* Intel MID platform SPI controller 1 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /* Intel MID platform SPI controller 2 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* Intel Elkhart Lake PSE SPI controllers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) { PCI_VDEVICE(INTEL, 0x4b84), (kernel_ulong_t)&spi_pci_ehl_desc},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) { PCI_VDEVICE(INTEL, 0x4b85), (kernel_ulong_t)&spi_pci_ehl_desc},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) { PCI_VDEVICE(INTEL, 0x4b86), (kernel_ulong_t)&spi_pci_ehl_desc},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) { PCI_VDEVICE(INTEL, 0x4b87), (kernel_ulong_t)&spi_pci_ehl_desc},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) MODULE_DEVICE_TABLE(pci, pci_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static struct pci_driver dw_spi_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) .name = DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) .id_table = pci_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) .probe = spi_pci_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) .remove = spi_pci_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) .pm = &dw_spi_pm_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) module_pci_driver(dw_spi_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) MODULE_AUTHOR("Feng Tang <feng.tang@intel.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) MODULE_DESCRIPTION("PCI interface driver for DW SPI Core");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) MODULE_LICENSE("GPL v2");