1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Synopsys DesignWare Multimedia Card PCI Interface driver |
4 | * |
5 | * Copyright (C) 2012 Vayavya Labs Pvt. Ltd. |
6 | */ |
7 | |
8 | #include <linux/interrupt.h> |
9 | #include <linux/module.h> |
10 | #include <linux/io.h> |
11 | #include <linux/irq.h> |
12 | #include <linux/pci.h> |
13 | #include <linux/pm_runtime.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/mmc/host.h> |
16 | #include <linux/mmc/mmc.h> |
17 | #include "dw_mmc.h" |
18 | |
19 | #define PCI_BAR_NO 2 |
20 | #define SYNOPSYS_DW_MCI_VENDOR_ID 0x700 |
21 | #define SYNOPSYS_DW_MCI_DEVICE_ID 0x1107 |
22 | /* Defining the Capabilities */ |
23 | #define DW_MCI_CAPABILITIES (MMC_CAP_4_BIT_DATA | MMC_CAP_MMC_HIGHSPEED |\ |
24 | MMC_CAP_SD_HIGHSPEED | MMC_CAP_8_BIT_DATA |\ |
25 | MMC_CAP_SDIO_IRQ) |
26 | |
27 | static struct dw_mci_board pci_board_data = { |
28 | .caps = DW_MCI_CAPABILITIES, |
29 | .bus_hz = 33 * 1000 * 1000, |
30 | .detect_delay_ms = 200, |
31 | .fifo_depth = 32, |
32 | }; |
33 | |
34 | static int dw_mci_pci_probe(struct pci_dev *pdev, |
35 | const struct pci_device_id *entries) |
36 | { |
37 | struct dw_mci *host; |
38 | int ret; |
39 | |
40 | ret = pcim_enable_device(pdev); |
41 | if (ret) |
42 | return ret; |
43 | |
44 | host = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct dw_mci), GFP_KERNEL); |
45 | if (!host) |
46 | return -ENOMEM; |
47 | |
48 | host->irq = pdev->irq; |
49 | host->irq_flags = IRQF_SHARED; |
50 | host->dev = &pdev->dev; |
51 | host->pdata = &pci_board_data; |
52 | |
53 | ret = pcim_iomap_regions(pdev, mask: 1 << PCI_BAR_NO, name: pci_name(pdev)); |
54 | if (ret) |
55 | return ret; |
56 | |
57 | host->regs = pcim_iomap_table(pdev)[PCI_BAR_NO]; |
58 | |
59 | pci_set_master(dev: pdev); |
60 | |
61 | ret = dw_mci_probe(host); |
62 | if (ret) |
63 | return ret; |
64 | |
65 | pci_set_drvdata(pdev, data: host); |
66 | |
67 | return 0; |
68 | } |
69 | |
70 | static void dw_mci_pci_remove(struct pci_dev *pdev) |
71 | { |
72 | struct dw_mci *host = pci_get_drvdata(pdev); |
73 | |
74 | dw_mci_remove(host); |
75 | } |
76 | |
77 | static const struct dev_pm_ops dw_mci_pci_dev_pm_ops = { |
78 | SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, |
79 | pm_runtime_force_resume) |
80 | SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend, |
81 | dw_mci_runtime_resume, |
82 | NULL) |
83 | }; |
84 | |
85 | static const struct pci_device_id dw_mci_pci_id[] = { |
86 | { PCI_DEVICE(SYNOPSYS_DW_MCI_VENDOR_ID, SYNOPSYS_DW_MCI_DEVICE_ID) }, |
87 | {} |
88 | }; |
89 | MODULE_DEVICE_TABLE(pci, dw_mci_pci_id); |
90 | |
91 | static struct pci_driver dw_mci_pci_driver = { |
92 | .name = "dw_mmc_pci" , |
93 | .id_table = dw_mci_pci_id, |
94 | .probe = dw_mci_pci_probe, |
95 | .remove = dw_mci_pci_remove, |
96 | .driver = { |
97 | .pm = &dw_mci_pci_dev_pm_ops, |
98 | }, |
99 | }; |
100 | |
101 | module_pci_driver(dw_mci_pci_driver); |
102 | |
103 | MODULE_DESCRIPTION("DW Multimedia Card PCI Interface driver" ); |
104 | MODULE_AUTHOR("Shashidhar Hiremath <shashidharh@vayavyalabs.com>" ); |
105 | MODULE_LICENSE("GPL v2" ); |
106 | |