11cc0cbeaSTharun Kumar P // SPDX-License-Identifier: GPL-2.0 21cc0cbeaSTharun Kumar P // PCI1xxxx SPI driver 31cc0cbeaSTharun Kumar P // Copyright (C) 2022 Microchip Technology Inc. 41cc0cbeaSTharun Kumar P // Authors: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com> 51cc0cbeaSTharun Kumar P // Kumaravel Thiagarajan <Kumaravel.Thiagarajan@microchip.com> 61cc0cbeaSTharun Kumar P 71cc0cbeaSTharun Kumar P 81cc0cbeaSTharun Kumar P #include <linux/module.h> 91cc0cbeaSTharun Kumar P #include <linux/pci.h> 101cc0cbeaSTharun Kumar P #include <linux/spi/spi.h> 111cc0cbeaSTharun Kumar P #include <linux/delay.h> 121cc0cbeaSTharun Kumar P 131cc0cbeaSTharun Kumar P #define DRV_NAME "spi-pci1xxxx" 141cc0cbeaSTharun Kumar P 151cc0cbeaSTharun Kumar P #define SYS_FREQ_DEFAULT (62500000) 161cc0cbeaSTharun Kumar P 171cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_MAX_CLOCK_HZ (30000000) 181cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_CLK_20MHZ (20000000) 191cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_CLK_15MHZ (15000000) 201cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_CLK_12MHZ (12000000) 211cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_CLK_10MHZ (10000000) 221cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_MIN_CLOCK_HZ (2000000) 231cc0cbeaSTharun Kumar P 241cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_BUFFER_SIZE (320) 251cc0cbeaSTharun Kumar P 261cc0cbeaSTharun Kumar P #define SPI_MST_CTL_DEVSEL_MASK (GENMASK(27, 25)) 271cc0cbeaSTharun Kumar P #define SPI_MST_CTL_CMD_LEN_MASK (GENMASK(16, 8)) 281cc0cbeaSTharun Kumar P #define SPI_MST_CTL_SPEED_MASK (GENMASK(7, 5)) 291cc0cbeaSTharun Kumar P #define SPI_MSI_VECTOR_SEL_MASK (GENMASK(4, 4)) 301cc0cbeaSTharun Kumar P 311cc0cbeaSTharun Kumar P #define SPI_MST_CTL_FORCE_CE (BIT(4)) 321cc0cbeaSTharun Kumar P #define SPI_MST_CTL_MODE_SEL (BIT(2)) 331cc0cbeaSTharun Kumar P #define SPI_MST_CTL_GO (BIT(0)) 341cc0cbeaSTharun Kumar P 351cc0cbeaSTharun Kumar P #define SPI_MST1_ADDR_BASE (0x800) 361cc0cbeaSTharun Kumar P 371cc0cbeaSTharun Kumar P /* x refers to SPI Host Controller HW instance id in the below macros - 0 or 1 */ 381cc0cbeaSTharun Kumar P 391cc0cbeaSTharun Kumar P #define SPI_MST_CMD_BUF_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x00) 401cc0cbeaSTharun Kumar P #define SPI_MST_RSP_BUF_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x200) 411cc0cbeaSTharun Kumar P #define SPI_MST_CTL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x400) 421cc0cbeaSTharun Kumar P #define SPI_MST_EVENT_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x420) 431cc0cbeaSTharun Kumar P #define SPI_MST_EVENT_MASK_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x424) 441cc0cbeaSTharun Kumar P #define SPI_MST_PAD_CTL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x460) 451cc0cbeaSTharun Kumar P #define SPIALERT_MST_DB_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x464) 461cc0cbeaSTharun Kumar P #define SPIALERT_MST_VAL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x468) 471cc0cbeaSTharun Kumar P #define SPI_PCI_CTRL_REG_OFFSET(x) (((x) * SPI_MST1_ADDR_BASE) + 0x480) 481cc0cbeaSTharun Kumar P 491cc0cbeaSTharun Kumar P #define PCI1XXXX_IRQ_FLAGS (IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE) 501cc0cbeaSTharun Kumar P #define SPI_MAX_DATA_LEN 320 511cc0cbeaSTharun Kumar P 521cc0cbeaSTharun Kumar P #define PCI1XXXX_SPI_TIMEOUT (msecs_to_jiffies(100)) 531cc0cbeaSTharun Kumar P 541cc0cbeaSTharun Kumar P #define SPI_INTR BIT(8) 551cc0cbeaSTharun Kumar P #define SPI_FORCE_CE BIT(4) 561cc0cbeaSTharun Kumar P 571cc0cbeaSTharun Kumar P #define SPI_CHIP_SEL_COUNT 7 581cc0cbeaSTharun Kumar P #define VENDOR_ID_MCHP 0x1055 591cc0cbeaSTharun Kumar P 607ba63521STharun Kumar P #define SPI_SUSPEND_CONFIG 0x101 614266d216STharun Kumar P #define SPI_RESUME_CONFIG 0x203 627ba63521STharun Kumar P 631cc0cbeaSTharun Kumar P struct pci1xxxx_spi_internal { 641cc0cbeaSTharun Kumar P u8 hw_inst; 651cc0cbeaSTharun Kumar P bool spi_xfer_in_progress; 661cc0cbeaSTharun Kumar P int irq; 671cc0cbeaSTharun Kumar P struct completion spi_xfer_done; 68*f9977bb1SYang Yingliang struct spi_controller *spi_host; 691cc0cbeaSTharun Kumar P struct pci1xxxx_spi *parent; 701cc0cbeaSTharun Kumar P struct { 711cc0cbeaSTharun Kumar P unsigned int dev_sel : 3; 721cc0cbeaSTharun Kumar P unsigned int msi_vector_sel : 1; 731cc0cbeaSTharun Kumar P } prev_val; 741cc0cbeaSTharun Kumar P }; 751cc0cbeaSTharun Kumar P 761cc0cbeaSTharun Kumar P struct pci1xxxx_spi { 771cc0cbeaSTharun Kumar P struct pci_dev *dev; 781cc0cbeaSTharun Kumar P u8 total_hw_instances; 791cc0cbeaSTharun Kumar P void __iomem *reg_base; 801cc0cbeaSTharun Kumar P struct pci1xxxx_spi_internal *spi_int[]; 811cc0cbeaSTharun Kumar P }; 821cc0cbeaSTharun Kumar P 831cc0cbeaSTharun Kumar P static const struct pci_device_id pci1xxxx_spi_pci_id_table[] = { 841cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, 851cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, 861cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, 871cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa004, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, 881cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, 891cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, 901cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, 911cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa014, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, 921cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, 931cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, 941cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, 951cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa024, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, 961cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, 971cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, 981cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, 991cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa034, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, 1001cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0001), 0, 0, 0x02}, 1011cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0002), 0, 0, 0x01}, 1021cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, 0x0003), 0, 0, 0x11}, 1031cc0cbeaSTharun Kumar P { PCI_DEVICE_SUB(VENDOR_ID_MCHP, 0xa044, PCI_ANY_ID, PCI_ANY_ID), 0, 0, 0x01}, 1041cc0cbeaSTharun Kumar P { 0, } 1051cc0cbeaSTharun Kumar P }; 1061cc0cbeaSTharun Kumar P 1071cc0cbeaSTharun Kumar P MODULE_DEVICE_TABLE(pci, pci1xxxx_spi_pci_id_table); 1081cc0cbeaSTharun Kumar P 1091cc0cbeaSTharun Kumar P static void pci1xxxx_spi_set_cs(struct spi_device *spi, bool enable) 1101cc0cbeaSTharun Kumar P { 1111cc0cbeaSTharun Kumar P struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi->controller); 1121cc0cbeaSTharun Kumar P struct pci1xxxx_spi *par = p->parent; 1131cc0cbeaSTharun Kumar P u32 regval; 1141cc0cbeaSTharun Kumar P 1151cc0cbeaSTharun Kumar P /* Set the DEV_SEL bits of the SPI_MST_CTL_REG */ 1161cc0cbeaSTharun Kumar P regval = readl(par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst)); 11745d2af82STharun Kumar P if (!enable) { 11845d2af82STharun Kumar P regval |= SPI_FORCE_CE; 1191cc0cbeaSTharun Kumar P regval &= ~SPI_MST_CTL_DEVSEL_MASK; 1209e264f3fSAmit Kumar Mahapatra via Alsa-devel regval |= (spi_get_chipselect(spi, 0) << 25); 1211cc0cbeaSTharun Kumar P } else { 12245d2af82STharun Kumar P regval &= ~SPI_FORCE_CE; 1231cc0cbeaSTharun Kumar P } 12445d2af82STharun Kumar P writel(regval, par->reg_base + SPI_MST_CTL_REG_OFFSET(p->hw_inst)); 1251cc0cbeaSTharun Kumar P } 1261cc0cbeaSTharun Kumar P 1271cc0cbeaSTharun Kumar P static u8 pci1xxxx_get_clock_div(u32 hz) 1281cc0cbeaSTharun Kumar P { 1291cc0cbeaSTharun Kumar P u8 val = 0; 1301cc0cbeaSTharun Kumar P 1311cc0cbeaSTharun Kumar P if (hz >= PCI1XXXX_SPI_MAX_CLOCK_HZ) 1321cc0cbeaSTharun Kumar P val = 2; 1331cc0cbeaSTharun Kumar P else if ((hz < PCI1XXXX_SPI_MAX_CLOCK_HZ) && (hz >= PCI1XXXX_SPI_CLK_20MHZ)) 1341cc0cbeaSTharun Kumar P val = 3; 1351cc0cbeaSTharun Kumar P else if ((hz < PCI1XXXX_SPI_CLK_20MHZ) && (hz >= PCI1XXXX_SPI_CLK_15MHZ)) 1361cc0cbeaSTharun Kumar P val = 4; 1371cc0cbeaSTharun Kumar P else if ((hz < PCI1XXXX_SPI_CLK_15MHZ) && (hz >= PCI1XXXX_SPI_CLK_12MHZ)) 1381cc0cbeaSTharun Kumar P val = 5; 1391cc0cbeaSTharun Kumar P else if ((hz < PCI1XXXX_SPI_CLK_12MHZ) && (hz >= PCI1XXXX_SPI_CLK_10MHZ)) 1401cc0cbeaSTharun Kumar P val = 6; 1411cc0cbeaSTharun Kumar P else if ((hz < PCI1XXXX_SPI_CLK_10MHZ) && (hz >= PCI1XXXX_SPI_MIN_CLOCK_HZ)) 1421cc0cbeaSTharun Kumar P val = 7; 1431cc0cbeaSTharun Kumar P else 1441cc0cbeaSTharun Kumar P val = 2; 1451cc0cbeaSTharun Kumar P 1461cc0cbeaSTharun Kumar P return val; 1471cc0cbeaSTharun Kumar P } 1481cc0cbeaSTharun Kumar P 1491cc0cbeaSTharun Kumar P static int pci1xxxx_spi_transfer_one(struct spi_controller *spi_ctlr, 1501cc0cbeaSTharun Kumar P struct spi_device *spi, struct spi_transfer *xfer) 1511cc0cbeaSTharun Kumar P { 1521cc0cbeaSTharun Kumar P struct pci1xxxx_spi_internal *p = spi_controller_get_devdata(spi_ctlr); 1531cc0cbeaSTharun Kumar P int mode, len, loop_iter, transfer_len; 1541cc0cbeaSTharun Kumar P struct pci1xxxx_spi *par = p->parent; 1551cc0cbeaSTharun Kumar P unsigned long bytes_transfered; 1561cc0cbeaSTharun Kumar P unsigned long bytes_recvd; 1571cc0cbeaSTharun Kumar P unsigned long loop_count; 1581cc0cbeaSTharun Kumar P u8 *rx_buf, result; 1591cc0cbeaSTharun Kumar P const u8 *tx_buf; 1601cc0cbeaSTharun Kumar P u32 regval; 1611cc0cbeaSTharun Kumar P u8 clkdiv; 1621cc0cbeaSTharun Kumar P 1631cc0cbeaSTharun Kumar P p->spi_xfer_in_progress = true; 1641cc0cbeaSTharun Kumar P mode = spi->mode; 1651cc0cbeaSTharun Kumar P clkdiv = pci1xxxx_get_clock_div(xfer->speed_hz); 1661cc0cbeaSTharun Kumar P tx_buf = xfer->tx_buf; 1671cc0cbeaSTharun Kumar P rx_buf = xfer->rx_buf; 1681cc0cbeaSTharun Kumar P transfer_len = xfer->len; 1691cc0cbeaSTharun Kumar P regval = readl(par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); 1701cc0cbeaSTharun Kumar P writel(regval, par->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); 1711cc0cbeaSTharun Kumar P 1721cc0cbeaSTharun Kumar P if (tx_buf) { 1731cc0cbeaSTharun Kumar P bytes_transfered = 0; 1741cc0cbeaSTharun Kumar P bytes_recvd = 0; 1751cc0cbeaSTharun Kumar P loop_count = transfer_len / SPI_MAX_DATA_LEN; 1761cc0cbeaSTharun Kumar P if (transfer_len % SPI_MAX_DATA_LEN != 0) 1771cc0cbeaSTharun Kumar P loop_count += 1; 1781cc0cbeaSTharun Kumar P 1791cc0cbeaSTharun Kumar P for (loop_iter = 0; loop_iter < loop_count; loop_iter++) { 1801cc0cbeaSTharun Kumar P len = SPI_MAX_DATA_LEN; 1811cc0cbeaSTharun Kumar P if ((transfer_len % SPI_MAX_DATA_LEN != 0) && 1821cc0cbeaSTharun Kumar P (loop_iter == loop_count - 1)) 1831cc0cbeaSTharun Kumar P len = transfer_len % SPI_MAX_DATA_LEN; 1841cc0cbeaSTharun Kumar P 1851cc0cbeaSTharun Kumar P reinit_completion(&p->spi_xfer_done); 1861cc0cbeaSTharun Kumar P memcpy_toio(par->reg_base + SPI_MST_CMD_BUF_OFFSET(p->hw_inst), 1871cc0cbeaSTharun Kumar P &tx_buf[bytes_transfered], len); 1881cc0cbeaSTharun Kumar P bytes_transfered += len; 1891cc0cbeaSTharun Kumar P regval = readl(par->reg_base + 1901cc0cbeaSTharun Kumar P SPI_MST_CTL_REG_OFFSET(p->hw_inst)); 1911cc0cbeaSTharun Kumar P regval &= ~(SPI_MST_CTL_MODE_SEL | SPI_MST_CTL_CMD_LEN_MASK | 1921cc0cbeaSTharun Kumar P SPI_MST_CTL_SPEED_MASK); 1931cc0cbeaSTharun Kumar P 1941cc0cbeaSTharun Kumar P if (mode == SPI_MODE_3) 1951cc0cbeaSTharun Kumar P regval |= SPI_MST_CTL_MODE_SEL; 1961cc0cbeaSTharun Kumar P else 1971cc0cbeaSTharun Kumar P regval &= ~SPI_MST_CTL_MODE_SEL; 1981cc0cbeaSTharun Kumar P 19945d2af82STharun Kumar P regval |= (clkdiv << 5); 2001cc0cbeaSTharun Kumar P regval &= ~SPI_MST_CTL_CMD_LEN_MASK; 20135c8c5e5STharun Kumar P regval |= (len << 8); 2021cc0cbeaSTharun Kumar P writel(regval, par->reg_base + 2031cc0cbeaSTharun Kumar P SPI_MST_CTL_REG_OFFSET(p->hw_inst)); 2041cc0cbeaSTharun Kumar P regval = readl(par->reg_base + 2051cc0cbeaSTharun Kumar P SPI_MST_CTL_REG_OFFSET(p->hw_inst)); 2061cc0cbeaSTharun Kumar P regval |= SPI_MST_CTL_GO; 2071cc0cbeaSTharun Kumar P writel(regval, par->reg_base + 2081cc0cbeaSTharun Kumar P SPI_MST_CTL_REG_OFFSET(p->hw_inst)); 2091cc0cbeaSTharun Kumar P 2101cc0cbeaSTharun Kumar P /* Wait for DMA_TERM interrupt */ 2111cc0cbeaSTharun Kumar P result = wait_for_completion_timeout(&p->spi_xfer_done, 2121cc0cbeaSTharun Kumar P PCI1XXXX_SPI_TIMEOUT); 2131cc0cbeaSTharun Kumar P if (!result) 2141cc0cbeaSTharun Kumar P return -ETIMEDOUT; 2151cc0cbeaSTharun Kumar P 2161cc0cbeaSTharun Kumar P if (rx_buf) { 2171cc0cbeaSTharun Kumar P memcpy_fromio(&rx_buf[bytes_recvd], par->reg_base + 2181cc0cbeaSTharun Kumar P SPI_MST_RSP_BUF_OFFSET(p->hw_inst), len); 2191cc0cbeaSTharun Kumar P bytes_recvd += len; 2201cc0cbeaSTharun Kumar P } 2211cc0cbeaSTharun Kumar P } 2221cc0cbeaSTharun Kumar P } 2231cc0cbeaSTharun Kumar P p->spi_xfer_in_progress = false; 2241cc0cbeaSTharun Kumar P 2251cc0cbeaSTharun Kumar P return 0; 2261cc0cbeaSTharun Kumar P } 2271cc0cbeaSTharun Kumar P 2281cc0cbeaSTharun Kumar P static irqreturn_t pci1xxxx_spi_isr(int irq, void *dev) 2291cc0cbeaSTharun Kumar P { 2301cc0cbeaSTharun Kumar P struct pci1xxxx_spi_internal *p = dev; 2311cc0cbeaSTharun Kumar P irqreturn_t spi_int_fired = IRQ_NONE; 2321cc0cbeaSTharun Kumar P u32 regval; 2331cc0cbeaSTharun Kumar P 2341cc0cbeaSTharun Kumar P /* Clear the SPI GO_BIT Interrupt */ 2351cc0cbeaSTharun Kumar P regval = readl(p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); 2361cc0cbeaSTharun Kumar P if (regval & SPI_INTR) { 2371cc0cbeaSTharun Kumar P /* Clear xfer_done */ 2381cc0cbeaSTharun Kumar P complete(&p->spi_xfer_done); 2391cc0cbeaSTharun Kumar P spi_int_fired = IRQ_HANDLED; 2401cc0cbeaSTharun Kumar P } 2411cc0cbeaSTharun Kumar P 2421cc0cbeaSTharun Kumar P writel(regval, p->parent->reg_base + SPI_MST_EVENT_REG_OFFSET(p->hw_inst)); 2431cc0cbeaSTharun Kumar P 2441cc0cbeaSTharun Kumar P return spi_int_fired; 2451cc0cbeaSTharun Kumar P } 2461cc0cbeaSTharun Kumar P 2471cc0cbeaSTharun Kumar P static int pci1xxxx_spi_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 2481cc0cbeaSTharun Kumar P { 2491cc0cbeaSTharun Kumar P u8 hw_inst_cnt, iter, start, only_sec_inst; 2501cc0cbeaSTharun Kumar P struct pci1xxxx_spi_internal *spi_sub_ptr; 2511cc0cbeaSTharun Kumar P struct device *dev = &pdev->dev; 2521cc0cbeaSTharun Kumar P struct pci1xxxx_spi *spi_bus; 253*f9977bb1SYang Yingliang struct spi_controller *spi_host; 2541cc0cbeaSTharun Kumar P u32 regval; 2551cc0cbeaSTharun Kumar P int ret; 2561cc0cbeaSTharun Kumar P 2571cc0cbeaSTharun Kumar P hw_inst_cnt = ent->driver_data & 0x0f; 2581cc0cbeaSTharun Kumar P start = (ent->driver_data & 0xf0) >> 4; 2591cc0cbeaSTharun Kumar P if (start == 1) 2601cc0cbeaSTharun Kumar P only_sec_inst = 1; 2611cc0cbeaSTharun Kumar P else 2621cc0cbeaSTharun Kumar P only_sec_inst = 0; 2631cc0cbeaSTharun Kumar P 2641cc0cbeaSTharun Kumar P spi_bus = devm_kzalloc(&pdev->dev, 2651cc0cbeaSTharun Kumar P struct_size(spi_bus, spi_int, hw_inst_cnt), 2661cc0cbeaSTharun Kumar P GFP_KERNEL); 2671cc0cbeaSTharun Kumar P if (!spi_bus) 2681cc0cbeaSTharun Kumar P return -ENOMEM; 2691cc0cbeaSTharun Kumar P 2701cc0cbeaSTharun Kumar P spi_bus->dev = pdev; 2711cc0cbeaSTharun Kumar P spi_bus->total_hw_instances = hw_inst_cnt; 2721cc0cbeaSTharun Kumar P pci_set_master(pdev); 2731cc0cbeaSTharun Kumar P 2741cc0cbeaSTharun Kumar P for (iter = 0; iter < hw_inst_cnt; iter++) { 2751cc0cbeaSTharun Kumar P spi_bus->spi_int[iter] = devm_kzalloc(&pdev->dev, 2761cc0cbeaSTharun Kumar P sizeof(struct pci1xxxx_spi_internal), 2771cc0cbeaSTharun Kumar P GFP_KERNEL); 2781cc0cbeaSTharun Kumar P spi_sub_ptr = spi_bus->spi_int[iter]; 279*f9977bb1SYang Yingliang spi_sub_ptr->spi_host = devm_spi_alloc_host(dev, sizeof(struct spi_controller)); 2801cc0cbeaSTharun Kumar P if (!spi_sub_ptr->spi_host) 2811cc0cbeaSTharun Kumar P return -ENOMEM; 2821cc0cbeaSTharun Kumar P 2831cc0cbeaSTharun Kumar P spi_sub_ptr->parent = spi_bus; 2841cc0cbeaSTharun Kumar P spi_sub_ptr->spi_xfer_in_progress = false; 2851cc0cbeaSTharun Kumar P 2861cc0cbeaSTharun Kumar P if (!iter) { 2871cc0cbeaSTharun Kumar P ret = pcim_enable_device(pdev); 2881cc0cbeaSTharun Kumar P if (ret) 2891cc0cbeaSTharun Kumar P return -ENOMEM; 2901cc0cbeaSTharun Kumar P 2911cc0cbeaSTharun Kumar P ret = pci_request_regions(pdev, DRV_NAME); 2921cc0cbeaSTharun Kumar P if (ret) 2931cc0cbeaSTharun Kumar P return -ENOMEM; 2941cc0cbeaSTharun Kumar P 2951cc0cbeaSTharun Kumar P spi_bus->reg_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0)); 2961cc0cbeaSTharun Kumar P if (!spi_bus->reg_base) { 2971cc0cbeaSTharun Kumar P ret = -EINVAL; 2981cc0cbeaSTharun Kumar P goto error; 2991cc0cbeaSTharun Kumar P } 3001cc0cbeaSTharun Kumar P 3011cc0cbeaSTharun Kumar P ret = pci_alloc_irq_vectors(pdev, hw_inst_cnt, hw_inst_cnt, 3021cc0cbeaSTharun Kumar P PCI_IRQ_ALL_TYPES); 3031cc0cbeaSTharun Kumar P if (ret < 0) { 3041cc0cbeaSTharun Kumar P dev_err(&pdev->dev, "Error allocating MSI vectors\n"); 3051cc0cbeaSTharun Kumar P goto error; 3061cc0cbeaSTharun Kumar P } 3071cc0cbeaSTharun Kumar P 3081cc0cbeaSTharun Kumar P init_completion(&spi_sub_ptr->spi_xfer_done); 3091cc0cbeaSTharun Kumar P /* Initialize Interrupts - SPI_INT */ 3101cc0cbeaSTharun Kumar P regval = readl(spi_bus->reg_base + 3111cc0cbeaSTharun Kumar P SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst)); 3121cc0cbeaSTharun Kumar P regval &= ~SPI_INTR; 3131cc0cbeaSTharun Kumar P writel(regval, spi_bus->reg_base + 3141cc0cbeaSTharun Kumar P SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst)); 3151cc0cbeaSTharun Kumar P spi_sub_ptr->irq = pci_irq_vector(pdev, 0); 3161cc0cbeaSTharun Kumar P 3171cc0cbeaSTharun Kumar P ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq, 3181cc0cbeaSTharun Kumar P pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS, 3191cc0cbeaSTharun Kumar P pci_name(pdev), spi_sub_ptr); 3201cc0cbeaSTharun Kumar P if (ret < 0) { 3211cc0cbeaSTharun Kumar P dev_err(&pdev->dev, "Unable to request irq : %d", 3221cc0cbeaSTharun Kumar P spi_sub_ptr->irq); 3231cc0cbeaSTharun Kumar P ret = -ENODEV; 3241cc0cbeaSTharun Kumar P goto error; 3251cc0cbeaSTharun Kumar P } 3261cc0cbeaSTharun Kumar P 3271cc0cbeaSTharun Kumar P /* This register is only applicable for 1st instance */ 3281cc0cbeaSTharun Kumar P regval = readl(spi_bus->reg_base + SPI_PCI_CTRL_REG_OFFSET(0)); 3291cc0cbeaSTharun Kumar P if (!only_sec_inst) 3301cc0cbeaSTharun Kumar P regval |= (BIT(4)); 3311cc0cbeaSTharun Kumar P else 3321cc0cbeaSTharun Kumar P regval &= ~(BIT(4)); 3331cc0cbeaSTharun Kumar P 3341cc0cbeaSTharun Kumar P writel(regval, spi_bus->reg_base + SPI_PCI_CTRL_REG_OFFSET(0)); 3351cc0cbeaSTharun Kumar P } 3361cc0cbeaSTharun Kumar P 3371cc0cbeaSTharun Kumar P spi_sub_ptr->hw_inst = start++; 3381cc0cbeaSTharun Kumar P 3391cc0cbeaSTharun Kumar P if (iter == 1) { 3401cc0cbeaSTharun Kumar P init_completion(&spi_sub_ptr->spi_xfer_done); 3411cc0cbeaSTharun Kumar P /* Initialize Interrupts - SPI_INT */ 3421cc0cbeaSTharun Kumar P regval = readl(spi_bus->reg_base + 3431cc0cbeaSTharun Kumar P SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst)); 3441cc0cbeaSTharun Kumar P regval &= ~SPI_INTR; 3451cc0cbeaSTharun Kumar P writel(regval, spi_bus->reg_base + 3461cc0cbeaSTharun Kumar P SPI_MST_EVENT_MASK_REG_OFFSET(spi_sub_ptr->hw_inst)); 3471cc0cbeaSTharun Kumar P spi_sub_ptr->irq = pci_irq_vector(pdev, iter); 3481cc0cbeaSTharun Kumar P ret = devm_request_irq(&pdev->dev, spi_sub_ptr->irq, 3491cc0cbeaSTharun Kumar P pci1xxxx_spi_isr, PCI1XXXX_IRQ_FLAGS, 3501cc0cbeaSTharun Kumar P pci_name(pdev), spi_sub_ptr); 3511cc0cbeaSTharun Kumar P if (ret < 0) { 3521cc0cbeaSTharun Kumar P dev_err(&pdev->dev, "Unable to request irq : %d", 3531cc0cbeaSTharun Kumar P spi_sub_ptr->irq); 3541cc0cbeaSTharun Kumar P ret = -ENODEV; 3551cc0cbeaSTharun Kumar P goto error; 3561cc0cbeaSTharun Kumar P } 3571cc0cbeaSTharun Kumar P } 3581cc0cbeaSTharun Kumar P 3591cc0cbeaSTharun Kumar P spi_host = spi_sub_ptr->spi_host; 3601cc0cbeaSTharun Kumar P spi_host->num_chipselect = SPI_CHIP_SEL_COUNT; 3611cc0cbeaSTharun Kumar P spi_host->mode_bits = SPI_MODE_0 | SPI_MODE_3 | SPI_RX_DUAL | 3621cc0cbeaSTharun Kumar P SPI_TX_DUAL | SPI_LOOP; 3631cc0cbeaSTharun Kumar P spi_host->transfer_one = pci1xxxx_spi_transfer_one; 3641cc0cbeaSTharun Kumar P spi_host->set_cs = pci1xxxx_spi_set_cs; 3651cc0cbeaSTharun Kumar P spi_host->bits_per_word_mask = SPI_BPW_MASK(8); 3661cc0cbeaSTharun Kumar P spi_host->max_speed_hz = PCI1XXXX_SPI_MAX_CLOCK_HZ; 3671cc0cbeaSTharun Kumar P spi_host->min_speed_hz = PCI1XXXX_SPI_MIN_CLOCK_HZ; 36890366cd6SAndy Shevchenko spi_host->flags = SPI_CONTROLLER_MUST_TX; 369*f9977bb1SYang Yingliang spi_controller_set_devdata(spi_host, spi_sub_ptr); 370*f9977bb1SYang Yingliang ret = devm_spi_register_controller(dev, spi_host); 3711cc0cbeaSTharun Kumar P if (ret) 3721cc0cbeaSTharun Kumar P goto error; 3731cc0cbeaSTharun Kumar P } 3741cc0cbeaSTharun Kumar P pci_set_drvdata(pdev, spi_bus); 3751cc0cbeaSTharun Kumar P 3761cc0cbeaSTharun Kumar P return 0; 3771cc0cbeaSTharun Kumar P 3781cc0cbeaSTharun Kumar P error: 3791cc0cbeaSTharun Kumar P pci_release_regions(pdev); 3801cc0cbeaSTharun Kumar P return ret; 3811cc0cbeaSTharun Kumar P } 3821cc0cbeaSTharun Kumar P 3837ba63521STharun Kumar P static void store_restore_config(struct pci1xxxx_spi *spi_ptr, 3847ba63521STharun Kumar P struct pci1xxxx_spi_internal *spi_sub_ptr, 3857ba63521STharun Kumar P u8 inst, bool store) 3867ba63521STharun Kumar P { 3877ba63521STharun Kumar P u32 regval; 3887ba63521STharun Kumar P 3897ba63521STharun Kumar P if (store) { 3907ba63521STharun Kumar P regval = readl(spi_ptr->reg_base + 3917ba63521STharun Kumar P SPI_MST_CTL_REG_OFFSET(spi_sub_ptr->hw_inst)); 3927ba63521STharun Kumar P regval &= SPI_MST_CTL_DEVSEL_MASK; 3937ba63521STharun Kumar P spi_sub_ptr->prev_val.dev_sel = (regval >> 25) & 7; 3947ba63521STharun Kumar P regval = readl(spi_ptr->reg_base + 3957ba63521STharun Kumar P SPI_PCI_CTRL_REG_OFFSET(spi_sub_ptr->hw_inst)); 3967ba63521STharun Kumar P regval &= SPI_MSI_VECTOR_SEL_MASK; 3977ba63521STharun Kumar P spi_sub_ptr->prev_val.msi_vector_sel = (regval >> 4) & 1; 3987ba63521STharun Kumar P } else { 3997ba63521STharun Kumar P regval = readl(spi_ptr->reg_base + SPI_MST_CTL_REG_OFFSET(inst)); 4007ba63521STharun Kumar P regval &= ~SPI_MST_CTL_DEVSEL_MASK; 4017ba63521STharun Kumar P regval |= (spi_sub_ptr->prev_val.dev_sel << 25); 4027ba63521STharun Kumar P writel(regval, 4037ba63521STharun Kumar P spi_ptr->reg_base + SPI_MST_CTL_REG_OFFSET(inst)); 4047ba63521STharun Kumar P writel((spi_sub_ptr->prev_val.msi_vector_sel << 4), 4057ba63521STharun Kumar P spi_ptr->reg_base + SPI_PCI_CTRL_REG_OFFSET(inst)); 4067ba63521STharun Kumar P } 4077ba63521STharun Kumar P } 4087ba63521STharun Kumar P 4097ba63521STharun Kumar P static int pci1xxxx_spi_resume(struct device *dev) 4107ba63521STharun Kumar P { 4117ba63521STharun Kumar P struct pci1xxxx_spi *spi_ptr = dev_get_drvdata(dev); 4127ba63521STharun Kumar P struct pci1xxxx_spi_internal *spi_sub_ptr; 4137ba63521STharun Kumar P u32 regval = SPI_RESUME_CONFIG; 4147ba63521STharun Kumar P u8 iter; 4157ba63521STharun Kumar P 4167ba63521STharun Kumar P for (iter = 0; iter < spi_ptr->total_hw_instances; iter++) { 4177ba63521STharun Kumar P spi_sub_ptr = spi_ptr->spi_int[iter]; 418*f9977bb1SYang Yingliang spi_controller_resume(spi_sub_ptr->spi_host); 4197ba63521STharun Kumar P writel(regval, spi_ptr->reg_base + 4207ba63521STharun Kumar P SPI_MST_EVENT_MASK_REG_OFFSET(iter)); 4217ba63521STharun Kumar P 4227ba63521STharun Kumar P /* Restore config at resume */ 4237ba63521STharun Kumar P store_restore_config(spi_ptr, spi_sub_ptr, iter, 0); 4247ba63521STharun Kumar P } 4257ba63521STharun Kumar P 4267ba63521STharun Kumar P return 0; 4277ba63521STharun Kumar P } 4287ba63521STharun Kumar P 4297ba63521STharun Kumar P static int pci1xxxx_spi_suspend(struct device *dev) 4307ba63521STharun Kumar P { 4317ba63521STharun Kumar P struct pci1xxxx_spi *spi_ptr = dev_get_drvdata(dev); 4327ba63521STharun Kumar P struct pci1xxxx_spi_internal *spi_sub_ptr; 4337ba63521STharun Kumar P u32 reg1 = SPI_SUSPEND_CONFIG; 4347ba63521STharun Kumar P u8 iter; 4357ba63521STharun Kumar P 4367ba63521STharun Kumar P for (iter = 0; iter < spi_ptr->total_hw_instances; iter++) { 4377ba63521STharun Kumar P spi_sub_ptr = spi_ptr->spi_int[iter]; 4387ba63521STharun Kumar P 4397ba63521STharun Kumar P while (spi_sub_ptr->spi_xfer_in_progress) 4407ba63521STharun Kumar P msleep(20); 4417ba63521STharun Kumar P 4427ba63521STharun Kumar P /* Store existing config before suspend */ 4437ba63521STharun Kumar P store_restore_config(spi_ptr, spi_sub_ptr, iter, 1); 444*f9977bb1SYang Yingliang spi_controller_suspend(spi_sub_ptr->spi_host); 4457ba63521STharun Kumar P writel(reg1, spi_ptr->reg_base + 4467ba63521STharun Kumar P SPI_MST_EVENT_MASK_REG_OFFSET(iter)); 4477ba63521STharun Kumar P } 4487ba63521STharun Kumar P 4497ba63521STharun Kumar P return 0; 4507ba63521STharun Kumar P } 4517ba63521STharun Kumar P 4527ba63521STharun Kumar P static DEFINE_SIMPLE_DEV_PM_OPS(spi_pm_ops, pci1xxxx_spi_suspend, 4537ba63521STharun Kumar P pci1xxxx_spi_resume); 4547ba63521STharun Kumar P 4551cc0cbeaSTharun Kumar P static struct pci_driver pci1xxxx_spi_driver = { 4561cc0cbeaSTharun Kumar P .name = DRV_NAME, 4571cc0cbeaSTharun Kumar P .id_table = pci1xxxx_spi_pci_id_table, 4581cc0cbeaSTharun Kumar P .probe = pci1xxxx_spi_probe, 4597ba63521STharun Kumar P .driver = { 4607ba63521STharun Kumar P .pm = pm_sleep_ptr(&spi_pm_ops), 4617ba63521STharun Kumar P }, 4621cc0cbeaSTharun Kumar P }; 4631cc0cbeaSTharun Kumar P 4641cc0cbeaSTharun Kumar P module_pci_driver(pci1xxxx_spi_driver); 4651cc0cbeaSTharun Kumar P 4661cc0cbeaSTharun Kumar P MODULE_DESCRIPTION("Microchip Technology Inc. pci1xxxx SPI bus driver"); 4671cc0cbeaSTharun Kumar P MODULE_AUTHOR("Tharun Kumar P<tharunkumar.pasumarthi@microchip.com>"); 4681cc0cbeaSTharun Kumar P MODULE_AUTHOR("Kumaravel Thiagarajan<kumaravel.thiagarajan@microchip.com>"); 4691cc0cbeaSTharun Kumar P MODULE_LICENSE("GPL v2"); 470