Commit 03b1781aa978aab345b5a85d8596f8615281ba89
Committed by
James Bottomley
1 parent
39c60a0948
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
[SCSI] ufs: Add Platform glue driver for ufshcd
This patch adds Platform glue driver for ufshcd. Reviewed-by: Arnd Bergmann <arnd@arndb.de> Reviewed-by: Namjae Jeon <linkinjeon@gmail.com> Reviewed-by: Subhash Jadavani <subhashj@codeaurora.org> Reviewed-by: Sujit Reddy Thumma <sthumma@codeaurora.org> Tested-by: Maya Erez <merez@codeaurora.org> Signed-off-by: Vinayak Holikatti <vinholikatti@gmail.com> Signed-off-by: Santosh Yaraganavi <santoshsy@gmail.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Showing 3 changed files with 229 additions and 0 deletions Side-by-side Diff
drivers/scsi/ufs/Kconfig
... | ... | @@ -57,4 +57,15 @@ |
57 | 57 | If you have a controller with this interface, say Y or M here. |
58 | 58 | |
59 | 59 | If unsure, say N. |
60 | + | |
61 | +config SCSI_UFSHCD_PLATFORM | |
62 | + tristate "Platform bus based UFS Controller support" | |
63 | + depends on SCSI_UFSHCD | |
64 | + ---help--- | |
65 | + This selects the UFS host controller support. Select this if | |
66 | + you have an UFS controller on Platform bus. | |
67 | + | |
68 | + If you have a controller with this interface, say Y or M here. | |
69 | + | |
70 | + If unsure, say N. |
drivers/scsi/ufs/Makefile
drivers/scsi/ufs/ufshcd-pltfrm.c
1 | +/* | |
2 | + * Universal Flash Storage Host controller Platform bus based glue driver | |
3 | + * | |
4 | + * This code is based on drivers/scsi/ufs/ufshcd-pltfrm.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/platform_device.h> | |
38 | + | |
39 | +#ifdef CONFIG_PM | |
40 | +/** | |
41 | + * ufshcd_pltfrm_suspend - suspend power management function | |
42 | + * @dev: pointer to device handle | |
43 | + * | |
44 | + * | |
45 | + * Returns 0 | |
46 | + */ | |
47 | +static int ufshcd_pltfrm_suspend(struct device *dev) | |
48 | +{ | |
49 | + struct platform_device *pdev = to_platform_device(dev); | |
50 | + struct ufs_hba *hba = platform_get_drvdata(pdev); | |
51 | + | |
52 | + /* | |
53 | + * TODO: | |
54 | + * 1. Call ufshcd_suspend | |
55 | + * 2. Do bus specific power management | |
56 | + */ | |
57 | + | |
58 | + disable_irq(hba->irq); | |
59 | + | |
60 | + return 0; | |
61 | +} | |
62 | + | |
63 | +/** | |
64 | + * ufshcd_pltfrm_resume - resume power management function | |
65 | + * @dev: pointer to device handle | |
66 | + * | |
67 | + * Returns 0 | |
68 | + */ | |
69 | +static int ufshcd_pltfrm_resume(struct device *dev) | |
70 | +{ | |
71 | + struct platform_device *pdev = to_platform_device(dev); | |
72 | + struct ufs_hba *hba = platform_get_drvdata(pdev); | |
73 | + | |
74 | + /* | |
75 | + * TODO: | |
76 | + * 1. Call ufshcd_resume. | |
77 | + * 2. Do bus specific wake up | |
78 | + */ | |
79 | + | |
80 | + enable_irq(hba->irq); | |
81 | + | |
82 | + return 0; | |
83 | +} | |
84 | +#else | |
85 | +#define ufshcd_pltfrm_suspend NULL | |
86 | +#define ufshcd_pltfrm_resume NULL | |
87 | +#endif | |
88 | + | |
89 | +/** | |
90 | + * ufshcd_pltfrm_probe - probe routine of the driver | |
91 | + * @pdev: pointer to Platform device handle | |
92 | + * | |
93 | + * Returns 0 on success, non-zero value on failure | |
94 | + */ | |
95 | +static int ufshcd_pltfrm_probe(struct platform_device *pdev) | |
96 | +{ | |
97 | + struct ufs_hba *hba; | |
98 | + void __iomem *mmio_base; | |
99 | + struct resource *mem_res; | |
100 | + struct resource *irq_res; | |
101 | + resource_size_t mem_size; | |
102 | + int err; | |
103 | + struct device *dev = &pdev->dev; | |
104 | + | |
105 | + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
106 | + if (!mem_res) { | |
107 | + dev_err(&pdev->dev, | |
108 | + "Memory resource not available\n"); | |
109 | + err = -ENODEV; | |
110 | + goto out_error; | |
111 | + } | |
112 | + | |
113 | + mem_size = resource_size(mem_res); | |
114 | + if (!request_mem_region(mem_res->start, mem_size, "ufshcd")) { | |
115 | + dev_err(&pdev->dev, | |
116 | + "Cannot reserve the memory resource\n"); | |
117 | + err = -EBUSY; | |
118 | + goto out_error; | |
119 | + } | |
120 | + | |
121 | + mmio_base = ioremap_nocache(mem_res->start, mem_size); | |
122 | + if (!mmio_base) { | |
123 | + dev_err(&pdev->dev, "memory map failed\n"); | |
124 | + err = -ENOMEM; | |
125 | + goto out_release_regions; | |
126 | + } | |
127 | + | |
128 | + irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | |
129 | + if (!irq_res) { | |
130 | + dev_err(&pdev->dev, "IRQ resource not available\n"); | |
131 | + err = -ENODEV; | |
132 | + goto out_iounmap; | |
133 | + } | |
134 | + | |
135 | + err = dma_set_coherent_mask(dev, dev->coherent_dma_mask); | |
136 | + if (err) { | |
137 | + dev_err(&pdev->dev, "set dma mask failed\n"); | |
138 | + goto out_iounmap; | |
139 | + } | |
140 | + | |
141 | + err = ufshcd_init(&pdev->dev, &hba, mmio_base, irq_res->start); | |
142 | + if (err) { | |
143 | + dev_err(&pdev->dev, "Intialization failed\n"); | |
144 | + goto out_iounmap; | |
145 | + } | |
146 | + | |
147 | + platform_set_drvdata(pdev, hba); | |
148 | + | |
149 | + return 0; | |
150 | + | |
151 | +out_iounmap: | |
152 | + iounmap(mmio_base); | |
153 | +out_release_regions: | |
154 | + release_mem_region(mem_res->start, mem_size); | |
155 | +out_error: | |
156 | + return err; | |
157 | +} | |
158 | + | |
159 | +/** | |
160 | + * ufshcd_pltfrm_remove - remove platform driver routine | |
161 | + * @pdev: pointer to platform device handle | |
162 | + * | |
163 | + * Returns 0 on success, non-zero value on failure | |
164 | + */ | |
165 | +static int ufshcd_pltfrm_remove(struct platform_device *pdev) | |
166 | +{ | |
167 | + struct resource *mem_res; | |
168 | + resource_size_t mem_size; | |
169 | + struct ufs_hba *hba = platform_get_drvdata(pdev); | |
170 | + | |
171 | + disable_irq(hba->irq); | |
172 | + | |
173 | + /* Some buggy controllers raise interrupt after | |
174 | + * the resources are removed. So first we unregister the | |
175 | + * irq handler and then the resources used by driver | |
176 | + */ | |
177 | + | |
178 | + free_irq(hba->irq, hba); | |
179 | + ufshcd_remove(hba); | |
180 | + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
181 | + if (!mem_res) | |
182 | + dev_err(&pdev->dev, "ufshcd: Memory resource not available\n"); | |
183 | + else { | |
184 | + mem_size = resource_size(mem_res); | |
185 | + release_mem_region(mem_res->start, mem_size); | |
186 | + } | |
187 | + platform_set_drvdata(pdev, NULL); | |
188 | + return 0; | |
189 | +} | |
190 | + | |
191 | +static const struct of_device_id ufs_of_match[] = { | |
192 | + { .compatible = "jedec,ufs-1.1"}, | |
193 | +}; | |
194 | + | |
195 | +static const struct dev_pm_ops ufshcd_dev_pm_ops = { | |
196 | + .suspend = ufshcd_pltfrm_suspend, | |
197 | + .resume = ufshcd_pltfrm_resume, | |
198 | +}; | |
199 | + | |
200 | +static struct platform_driver ufshcd_pltfrm_driver = { | |
201 | + .probe = ufshcd_pltfrm_probe, | |
202 | + .remove = ufshcd_pltfrm_remove, | |
203 | + .driver = { | |
204 | + .name = "ufshcd", | |
205 | + .owner = THIS_MODULE, | |
206 | + .pm = &ufshcd_dev_pm_ops, | |
207 | + .of_match_table = ufs_of_match, | |
208 | + }, | |
209 | +}; | |
210 | + | |
211 | +module_platform_driver(ufshcd_pltfrm_driver); | |
212 | + | |
213 | +MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); | |
214 | +MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); | |
215 | +MODULE_DESCRIPTION("UFS host controller Pltform bus based glue driver"); | |
216 | +MODULE_LICENSE("GPL"); | |
217 | +MODULE_VERSION(UFSHCD_DRIVER_VERSION); |