Commit | Line | Data |
---|---|---|
99f2a8ae BD |
1 | /* drivers/mtd/maps/plat-ram.c |
2 | * | |
3 | * (c) 2004-2005 Simtec Electronics | |
4 | * http://www.simtec.co.uk/products/SWLINUX/ | |
5 | * Ben Dooks <ben@simtec.co.uk> | |
6 | * | |
7 | * Generic platfrom device based RAM map | |
8 | * | |
69f34c98 | 9 | * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $ |
99f2a8ae BD |
10 | * |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License as published by | |
13 | * the Free Software Foundation; either version 2 of the License, or | |
14 | * (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
24 | */ | |
25 | ||
99f2a8ae BD |
26 | #include <linux/module.h> |
27 | #include <linux/types.h> | |
28 | #include <linux/init.h> | |
29 | #include <linux/kernel.h> | |
30 | #include <linux/string.h> | |
31 | #include <linux/ioport.h> | |
32 | #include <linux/device.h> | |
4e57b681 | 33 | #include <linux/slab.h> |
d052d1be | 34 | #include <linux/platform_device.h> |
99f2a8ae BD |
35 | |
36 | #include <linux/mtd/mtd.h> | |
37 | #include <linux/mtd/map.h> | |
38 | #include <linux/mtd/partitions.h> | |
39 | #include <linux/mtd/plat-ram.h> | |
40 | ||
41 | #include <asm/io.h> | |
42 | ||
43 | /* private structure for each mtd platform ram device created */ | |
44 | ||
45 | struct platram_info { | |
46 | struct device *dev; | |
47 | struct mtd_info *mtd; | |
48 | struct map_info map; | |
49 | struct mtd_partition *partitions; | |
75757006 | 50 | bool free_partitions; |
99f2a8ae BD |
51 | struct resource *area; |
52 | struct platdata_mtd_ram *pdata; | |
53 | }; | |
54 | ||
55 | /* to_platram_info() | |
56 | * | |
57 | * device private data to struct platram_info conversion | |
58 | */ | |
59 | ||
3ae5eaec | 60 | static inline struct platram_info *to_platram_info(struct platform_device *dev) |
99f2a8ae | 61 | { |
3ae5eaec | 62 | return (struct platram_info *)platform_get_drvdata(dev); |
99f2a8ae BD |
63 | } |
64 | ||
65 | /* platram_setrw | |
66 | * | |
67 | * call the platform device's set rw/ro control | |
68 | * | |
69 | * to = 0 => read-only | |
70 | * = 1 => read-write | |
71 | */ | |
72 | ||
73 | static inline void platram_setrw(struct platram_info *info, int to) | |
74 | { | |
75 | if (info->pdata == NULL) | |
76 | return; | |
77 | ||
78 | if (info->pdata->set_rw != NULL) | |
79 | (info->pdata->set_rw)(info->dev, to); | |
80 | } | |
81 | ||
82 | /* platram_remove | |
83 | * | |
84 | * called to remove the device from the driver's control | |
85 | */ | |
86 | ||
3ae5eaec | 87 | static int platram_remove(struct platform_device *pdev) |
99f2a8ae | 88 | { |
3ae5eaec | 89 | struct platram_info *info = to_platram_info(pdev); |
99f2a8ae | 90 | |
3ae5eaec | 91 | platform_set_drvdata(pdev, NULL); |
99f2a8ae | 92 | |
3ae5eaec | 93 | dev_dbg(&pdev->dev, "removing device\n"); |
99f2a8ae | 94 | |
69f34c98 | 95 | if (info == NULL) |
99f2a8ae BD |
96 | return 0; |
97 | ||
98 | if (info->mtd) { | |
99 | #ifdef CONFIG_MTD_PARTITIONS | |
100 | if (info->partitions) { | |
101 | del_mtd_partitions(info->mtd); | |
75757006 FF |
102 | if (info->free_partitions) |
103 | kfree(info->partitions); | |
99f2a8ae BD |
104 | } |
105 | #endif | |
106 | del_mtd_device(info->mtd); | |
107 | map_destroy(info->mtd); | |
108 | } | |
109 | ||
110 | /* ensure ram is left read-only */ | |
111 | ||
112 | platram_setrw(info, PLATRAM_RO); | |
113 | ||
114 | /* release resources */ | |
115 | ||
116 | if (info->area) { | |
117 | release_resource(info->area); | |
118 | kfree(info->area); | |
119 | } | |
120 | ||
121 | if (info->map.virt != NULL) | |
122 | iounmap(info->map.virt); | |
69f34c98 | 123 | |
99f2a8ae BD |
124 | kfree(info); |
125 | ||
126 | return 0; | |
127 | } | |
128 | ||
129 | /* platram_probe | |
130 | * | |
131 | * called from device drive system when a device matching our | |
132 | * driver is found. | |
133 | */ | |
134 | ||
3ae5eaec | 135 | static int platram_probe(struct platform_device *pdev) |
99f2a8ae | 136 | { |
99f2a8ae BD |
137 | struct platdata_mtd_ram *pdata; |
138 | struct platram_info *info; | |
139 | struct resource *res; | |
140 | int err = 0; | |
141 | ||
3ae5eaec | 142 | dev_dbg(&pdev->dev, "probe entered\n"); |
69f34c98 | 143 | |
3ae5eaec RK |
144 | if (pdev->dev.platform_data == NULL) { |
145 | dev_err(&pdev->dev, "no platform data supplied\n"); | |
99f2a8ae BD |
146 | err = -ENOENT; |
147 | goto exit_error; | |
148 | } | |
149 | ||
3ae5eaec | 150 | pdata = pdev->dev.platform_data; |
99f2a8ae | 151 | |
95b93a0c | 152 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
99f2a8ae | 153 | if (info == NULL) { |
3ae5eaec | 154 | dev_err(&pdev->dev, "no memory for flash info\n"); |
99f2a8ae BD |
155 | err = -ENOMEM; |
156 | goto exit_error; | |
157 | } | |
158 | ||
3ae5eaec | 159 | platform_set_drvdata(pdev, info); |
99f2a8ae | 160 | |
3ae5eaec | 161 | info->dev = &pdev->dev; |
99f2a8ae BD |
162 | info->pdata = pdata; |
163 | ||
164 | /* get the resource for the memory mapping */ | |
165 | ||
3ae5eaec | 166 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
99f2a8ae BD |
167 | |
168 | if (res == NULL) { | |
3ae5eaec | 169 | dev_err(&pdev->dev, "no memory resource specified\n"); |
99f2a8ae BD |
170 | err = -ENOENT; |
171 | goto exit_free; | |
172 | } | |
173 | ||
06d63cc5 RD |
174 | dev_dbg(&pdev->dev, "got platform resource %p (0x%llx)\n", res, |
175 | (unsigned long long)res->start); | |
99f2a8ae BD |
176 | |
177 | /* setup map parameters */ | |
178 | ||
179 | info->map.phys = res->start; | |
180 | info->map.size = (res->end - res->start) + 1; | |
75757006 FF |
181 | info->map.name = pdata->mapname != NULL ? |
182 | (char *)pdata->mapname : (char *)pdev->name; | |
99f2a8ae BD |
183 | info->map.bankwidth = pdata->bankwidth; |
184 | ||
185 | /* register our usage of the memory area */ | |
186 | ||
3ae5eaec | 187 | info->area = request_mem_region(res->start, info->map.size, pdev->name); |
99f2a8ae | 188 | if (info->area == NULL) { |
3ae5eaec | 189 | dev_err(&pdev->dev, "failed to request memory region\n"); |
99f2a8ae BD |
190 | err = -EIO; |
191 | goto exit_free; | |
192 | } | |
193 | ||
194 | /* remap the memory area */ | |
195 | ||
196 | info->map.virt = ioremap(res->start, info->map.size); | |
3ae5eaec | 197 | dev_dbg(&pdev->dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size); |
99f2a8ae BD |
198 | |
199 | if (info->map.virt == NULL) { | |
3ae5eaec | 200 | dev_err(&pdev->dev, "failed to ioremap() region\n"); |
99f2a8ae BD |
201 | err = -EIO; |
202 | goto exit_free; | |
203 | } | |
204 | ||
99f2a8ae BD |
205 | simple_map_init(&info->map); |
206 | ||
3ae5eaec | 207 | dev_dbg(&pdev->dev, "initialised map, probing for mtd\n"); |
99f2a8ae | 208 | |
75757006 FF |
209 | /* probe for the right mtd map driver |
210 | * supplied by the platform_data struct */ | |
211 | ||
212 | if (pdata->map_probes != 0) { | |
213 | const char **map_probes = pdata->map_probes; | |
214 | ||
215 | for ( ; !info->mtd && *map_probes; map_probes++) | |
216 | info->mtd = do_map_probe(*map_probes , &info->map); | |
217 | } | |
218 | /* fallback to map_ram */ | |
219 | else | |
220 | info->mtd = do_map_probe("map_ram", &info->map); | |
99f2a8ae | 221 | |
99f2a8ae | 222 | if (info->mtd == NULL) { |
3ae5eaec | 223 | dev_err(&pdev->dev, "failed to probe for map_ram\n"); |
99f2a8ae BD |
224 | err = -ENOMEM; |
225 | goto exit_free; | |
226 | } | |
227 | ||
228 | info->mtd->owner = THIS_MODULE; | |
229 | ||
230 | platram_setrw(info, PLATRAM_RW); | |
231 | ||
232 | /* check to see if there are any available partitions, or wether | |
233 | * to add this device whole */ | |
234 | ||
235 | #ifdef CONFIG_MTD_PARTITIONS | |
75757006 FF |
236 | if (!pdata->nr_partitions) { |
237 | /* try to probe using the supplied probe type */ | |
238 | if (pdata->probes) { | |
239 | err = parse_mtd_partitions(info->mtd, pdata->probes, | |
99f2a8ae | 240 | &info->partitions, 0); |
75757006 FF |
241 | info->free_partitions = 1; |
242 | if (err > 0) | |
243 | err = add_mtd_partitions(info->mtd, | |
244 | info->partitions, err); | |
99f2a8ae BD |
245 | } |
246 | } | |
75757006 FF |
247 | /* use the static mapping */ |
248 | else | |
249 | err = add_mtd_partitions(info->mtd, pdata->partitions, | |
250 | pdata->nr_partitions); | |
99f2a8ae BD |
251 | #endif /* CONFIG_MTD_PARTITIONS */ |
252 | ||
253 | if (add_mtd_device(info->mtd)) { | |
3ae5eaec | 254 | dev_err(&pdev->dev, "add_mtd_device() failed\n"); |
99f2a8ae BD |
255 | err = -ENOMEM; |
256 | } | |
69f34c98 | 257 | |
75757006 FF |
258 | if (!err) |
259 | dev_info(&pdev->dev, "registered mtd device\n"); | |
260 | ||
99f2a8ae BD |
261 | return err; |
262 | ||
263 | exit_free: | |
3ae5eaec | 264 | platram_remove(pdev); |
99f2a8ae BD |
265 | exit_error: |
266 | return err; | |
267 | } | |
268 | ||
269 | /* device driver info */ | |
270 | ||
41d867c9 KS |
271 | /* work with hotplug and coldplug */ |
272 | MODULE_ALIAS("platform:mtd-ram"); | |
273 | ||
3ae5eaec | 274 | static struct platform_driver platram_driver = { |
99f2a8ae BD |
275 | .probe = platram_probe, |
276 | .remove = platram_remove, | |
3ae5eaec RK |
277 | .driver = { |
278 | .name = "mtd-ram", | |
279 | .owner = THIS_MODULE, | |
280 | }, | |
99f2a8ae BD |
281 | }; |
282 | ||
283 | /* module init/exit */ | |
284 | ||
285 | static int __init platram_init(void) | |
286 | { | |
287 | printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n"); | |
3ae5eaec | 288 | return platform_driver_register(&platram_driver); |
99f2a8ae BD |
289 | } |
290 | ||
291 | static void __exit platram_exit(void) | |
292 | { | |
3ae5eaec | 293 | platform_driver_unregister(&platram_driver); |
99f2a8ae BD |
294 | } |
295 | ||
296 | module_init(platram_init); | |
297 | module_exit(platram_exit); | |
298 | ||
299 | MODULE_LICENSE("GPL"); | |
300 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | |
301 | MODULE_DESCRIPTION("MTD platform RAM map driver"); |