diff options
Diffstat (limited to 'drivers/scsi/ufs/ufshcd-pci.c')
-rw-r--r-- | drivers/scsi/ufs/ufshcd-pci.c | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/drivers/scsi/ufs/ufshcd-pci.c b/drivers/scsi/ufs/ufshcd-pci.c new file mode 100644 index 000000000000..5cb1d75f5868 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-pci.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Universal Flash Storage Host controller PCI glue driver | ||
3 | * | ||
4 | * This code is based on drivers/scsi/ufs/ufshcd-pci.c | ||
5 | * Copyright (C) 2011-2013 Samsung India Software Operations | ||
6 | * | ||
7 | * Authors: | ||
8 | * Santosh Yaraganavi <santosh.sy@samsung.com> | ||
9 | * Vinayak Holikatti <h.vinayak@samsung.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * See the COPYING file in the top-level directory or visit | ||
16 | * <http://www.gnu.org/licenses/gpl-2.0.html> | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * This program is provided "AS IS" and "WITH ALL FAULTS" and | ||
24 | * without warranty of any kind. You are solely responsible for | ||
25 | * determining the appropriateness of using and distributing | ||
26 | * the program and assume all risks associated with your exercise | ||
27 | * of rights with respect to the program, including but not limited | ||
28 | * to infringement of third party rights, the risks and costs of | ||
29 | * program errors, damage to or loss of data, programs or equipment, | ||
30 | * and unavailability or interruption of operations. Under no | ||
31 | * circumstances will the contributor of this Program be liable for | ||
32 | * any damages of any kind arising from your use or distribution of | ||
33 | * this program. | ||
34 | */ | ||
35 | |||
36 | #include "ufshcd.h" | ||
37 | #include <linux/pci.h> | ||
38 | |||
39 | #ifdef CONFIG_PM | ||
40 | /** | ||
41 | * ufshcd_pci_suspend - suspend power management function | ||
42 | * @pdev: pointer to PCI device handle | ||
43 | * @state: power state | ||
44 | * | ||
45 | * Returns -ENOSYS | ||
46 | */ | ||
47 | static int ufshcd_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
48 | { | ||
49 | /* | ||
50 | * TODO: | ||
51 | * 1. Call ufshcd_suspend | ||
52 | * 2. Do bus specific power management | ||
53 | */ | ||
54 | |||
55 | return -ENOSYS; | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * ufshcd_pci_resume - resume power management function | ||
60 | * @pdev: pointer to PCI device handle | ||
61 | * | ||
62 | * Returns -ENOSYS | ||
63 | */ | ||
64 | static int ufshcd_pci_resume(struct pci_dev *pdev) | ||
65 | { | ||
66 | /* | ||
67 | * TODO: | ||
68 | * 1. Call ufshcd_resume. | ||
69 | * 2. Do bus specific wake up | ||
70 | */ | ||
71 | |||
72 | return -ENOSYS; | ||
73 | } | ||
74 | #endif /* CONFIG_PM */ | ||
75 | |||
76 | /** | ||
77 | * ufshcd_pci_shutdown - main function to put the controller in reset state | ||
78 | * @pdev: pointer to PCI device handle | ||
79 | */ | ||
80 | static void ufshcd_pci_shutdown(struct pci_dev *pdev) | ||
81 | { | ||
82 | ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev)); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * ufshcd_pci_remove - de-allocate PCI/SCSI host and host memory space | ||
87 | * data structure memory | ||
88 | * @pdev - pointer to PCI handle | ||
89 | */ | ||
90 | static void ufshcd_pci_remove(struct pci_dev *pdev) | ||
91 | { | ||
92 | struct ufs_hba *hba = pci_get_drvdata(pdev); | ||
93 | |||
94 | disable_irq(pdev->irq); | ||
95 | free_irq(pdev->irq, hba); | ||
96 | ufshcd_remove(hba); | ||
97 | pci_release_regions(pdev); | ||
98 | pci_set_drvdata(pdev, NULL); | ||
99 | pci_clear_master(pdev); | ||
100 | pci_disable_device(pdev); | ||
101 | } | ||
102 | |||
103 | /** | ||
104 | * ufshcd_set_dma_mask - Set dma mask based on the controller | ||
105 | * addressing capability | ||
106 | * @pdev: PCI device structure | ||
107 | * | ||
108 | * Returns 0 for success, non-zero for failure | ||
109 | */ | ||
110 | static int ufshcd_set_dma_mask(struct pci_dev *pdev) | ||
111 | { | ||
112 | int err; | ||
113 | |||
114 | if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) | ||
115 | && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) | ||
116 | return 0; | ||
117 | err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
118 | if (!err) | ||
119 | err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
120 | return err; | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * ufshcd_pci_probe - probe routine of the driver | ||
125 | * @pdev: pointer to PCI device handle | ||
126 | * @id: PCI device id | ||
127 | * | ||
128 | * Returns 0 on success, non-zero value on failure | ||
129 | */ | ||
130 | static int | ||
131 | ufshcd_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
132 | { | ||
133 | struct ufs_hba *hba; | ||
134 | void __iomem *mmio_base; | ||
135 | int err; | ||
136 | |||
137 | err = pci_enable_device(pdev); | ||
138 | if (err) { | ||
139 | dev_err(&pdev->dev, "pci_enable_device failed\n"); | ||
140 | goto out_error; | ||
141 | } | ||
142 | |||
143 | pci_set_master(pdev); | ||
144 | |||
145 | |||
146 | err = pci_request_regions(pdev, UFSHCD); | ||
147 | if (err < 0) { | ||
148 | dev_err(&pdev->dev, "request regions failed\n"); | ||
149 | goto out_disable; | ||
150 | } | ||
151 | |||
152 | mmio_base = pci_ioremap_bar(pdev, 0); | ||
153 | if (!mmio_base) { | ||
154 | dev_err(&pdev->dev, "memory map failed\n"); | ||
155 | err = -ENOMEM; | ||
156 | goto out_release_regions; | ||
157 | } | ||
158 | |||
159 | err = ufshcd_set_dma_mask(pdev); | ||
160 | if (err) { | ||
161 | dev_err(&pdev->dev, "set dma mask failed\n"); | ||
162 | goto out_iounmap; | ||
163 | } | ||
164 | |||
165 | err = ufshcd_init(&pdev->dev, &hba, mmio_base, pdev->irq); | ||
166 | if (err) { | ||
167 | dev_err(&pdev->dev, "Initialization failed\n"); | ||
168 | goto out_iounmap; | ||
169 | } | ||
170 | |||
171 | pci_set_drvdata(pdev, hba); | ||
172 | |||
173 | return 0; | ||
174 | |||
175 | out_iounmap: | ||
176 | iounmap(mmio_base); | ||
177 | out_release_regions: | ||
178 | pci_release_regions(pdev); | ||
179 | out_disable: | ||
180 | pci_clear_master(pdev); | ||
181 | pci_disable_device(pdev); | ||
182 | out_error: | ||
183 | return err; | ||
184 | } | ||
185 | |||
186 | static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = { | ||
187 | { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | ||
188 | { } /* terminate list */ | ||
189 | }; | ||
190 | |||
191 | MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl); | ||
192 | |||
193 | static struct pci_driver ufshcd_pci_driver = { | ||
194 | .name = UFSHCD, | ||
195 | .id_table = ufshcd_pci_tbl, | ||
196 | .probe = ufshcd_pci_probe, | ||
197 | .remove = ufshcd_pci_remove, | ||
198 | .shutdown = ufshcd_pci_shutdown, | ||
199 | #ifdef CONFIG_PM | ||
200 | .suspend = ufshcd_pci_suspend, | ||
201 | .resume = ufshcd_pci_resume, | ||
202 | #endif | ||
203 | }; | ||
204 | |||
205 | module_pci_driver(ufshcd_pci_driver); | ||
206 | |||
207 | MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); | ||
208 | MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); | ||
209 | MODULE_DESCRIPTION("UFS host controller PCI glue driver"); | ||
210 | MODULE_LICENSE("GPL"); | ||
211 | MODULE_VERSION(UFSHCD_DRIVER_VERSION); | ||