0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <ufs/ufshcd.h>
0011 #include "ufshcd-dwc.h"
0012 #include "tc-dwc-g210.h"
0013
0014 #include <linux/module.h>
0015 #include <linux/pci.h>
0016 #include <linux/pm_runtime.h>
0017
0018
0019 #define TC_G210_20BIT 20
0020 #define TC_G210_40BIT 40
0021 #define TC_G210_INV 0
0022
0023 static int tc_type = TC_G210_INV;
0024 module_param(tc_type, int, 0);
0025 MODULE_PARM_DESC(tc_type, "Test Chip Type (20 = 20-bit, 40 = 40-bit)");
0026
0027
0028
0029
0030 static struct ufs_hba_variant_ops tc_dwc_g210_pci_hba_vops = {
0031 .name = "tc-dwc-g210-pci",
0032 .link_startup_notify = ufshcd_dwc_link_startup_notify,
0033 };
0034
0035
0036
0037
0038
0039 static void tc_dwc_g210_pci_shutdown(struct pci_dev *pdev)
0040 {
0041 ufshcd_shutdown((struct ufs_hba *)pci_get_drvdata(pdev));
0042 }
0043
0044
0045
0046
0047
0048
0049 static void tc_dwc_g210_pci_remove(struct pci_dev *pdev)
0050 {
0051 struct ufs_hba *hba = pci_get_drvdata(pdev);
0052
0053 pm_runtime_forbid(&pdev->dev);
0054 pm_runtime_get_noresume(&pdev->dev);
0055 ufshcd_remove(hba);
0056 }
0057
0058
0059
0060
0061
0062
0063
0064
0065 static int
0066 tc_dwc_g210_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
0067 {
0068 struct ufs_hba *hba;
0069 void __iomem *mmio_base;
0070 int err;
0071
0072
0073 if (tc_type == TC_G210_20BIT) {
0074 tc_dwc_g210_pci_hba_vops.phy_initialization =
0075 tc_dwc_g210_config_20_bit;
0076 } else if (tc_type == TC_G210_40BIT) {
0077 tc_dwc_g210_pci_hba_vops.phy_initialization =
0078 tc_dwc_g210_config_40_bit;
0079 } else {
0080 dev_err(&pdev->dev, "test chip version not specified\n");
0081 return -EPERM;
0082 }
0083
0084 err = pcim_enable_device(pdev);
0085 if (err) {
0086 dev_err(&pdev->dev, "pcim_enable_device failed\n");
0087 return err;
0088 }
0089
0090 pci_set_master(pdev);
0091
0092 err = pcim_iomap_regions(pdev, 1 << 0, UFSHCD);
0093 if (err < 0) {
0094 dev_err(&pdev->dev, "request and iomap failed\n");
0095 return err;
0096 }
0097
0098 mmio_base = pcim_iomap_table(pdev)[0];
0099
0100 err = ufshcd_alloc_host(&pdev->dev, &hba);
0101 if (err) {
0102 dev_err(&pdev->dev, "Allocation failed\n");
0103 return err;
0104 }
0105
0106 hba->vops = &tc_dwc_g210_pci_hba_vops;
0107
0108 err = ufshcd_init(hba, mmio_base, pdev->irq);
0109 if (err) {
0110 dev_err(&pdev->dev, "Initialization failed\n");
0111 return err;
0112 }
0113
0114 pm_runtime_put_noidle(&pdev->dev);
0115 pm_runtime_allow(&pdev->dev);
0116
0117 return 0;
0118 }
0119
0120 static const struct dev_pm_ops tc_dwc_g210_pci_pm_ops = {
0121 SET_SYSTEM_SLEEP_PM_OPS(ufshcd_system_suspend, ufshcd_system_resume)
0122 SET_RUNTIME_PM_OPS(ufshcd_runtime_suspend, ufshcd_runtime_resume, NULL)
0123 .prepare = ufshcd_suspend_prepare,
0124 .complete = ufshcd_resume_complete,
0125 };
0126
0127 static const struct pci_device_id tc_dwc_g210_pci_tbl[] = {
0128 { PCI_VENDOR_ID_SYNOPSYS, 0xB101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
0129 { PCI_VENDOR_ID_SYNOPSYS, 0xB102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
0130 { }
0131 };
0132
0133 MODULE_DEVICE_TABLE(pci, tc_dwc_g210_pci_tbl);
0134
0135 static struct pci_driver tc_dwc_g210_pci_driver = {
0136 .name = "tc-dwc-g210-pci",
0137 .id_table = tc_dwc_g210_pci_tbl,
0138 .probe = tc_dwc_g210_pci_probe,
0139 .remove = tc_dwc_g210_pci_remove,
0140 .shutdown = tc_dwc_g210_pci_shutdown,
0141 .driver = {
0142 .pm = &tc_dwc_g210_pci_pm_ops
0143 },
0144 };
0145
0146 module_pci_driver(tc_dwc_g210_pci_driver);
0147
0148 MODULE_AUTHOR("Joao Pinto <Joao.Pinto@synopsys.com>");
0149 MODULE_DESCRIPTION("Synopsys Test Chip G210 PCI glue driver");
0150 MODULE_LICENSE("Dual BSD/GPL");