• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*======================================================================
2 
3     drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver
4 
5     Copyright (C) 2000 ARM Limited
6     Copyright (C) 2003 Deep Blue Solutions Ltd.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21 
22    This is access code for flashes using ARM's flash partitioning
23    standards.
24 
25 ======================================================================*/
26 
27 #include <linux/module.h>
28 #include <linux/types.h>
29 #include <linux/kernel.h>
30 #include <linux/slab.h>
31 #include <linux/ioport.h>
32 #include <linux/platform_device.h>
33 #include <linux/init.h>
34 
35 #include <linux/mtd/mtd.h>
36 #include <linux/mtd/map.h>
37 #include <linux/mtd/partitions.h>
38 
39 #include <asm/mach/flash.h>
40 #include <mach/hardware.h>
41 #include <asm/io.h>
42 #include <asm/system.h>
43 
44 #ifdef CONFIG_ARCH_P720T
45 #define FLASH_BASE		(0x04000000)
46 #define FLASH_SIZE		(64*1024*1024)
47 #endif
48 
49 struct armflash_info {
50 	struct flash_platform_data *plat;
51 	struct resource		*res;
52 	struct mtd_partition	*parts;
53 	struct mtd_info		*mtd;
54 	struct map_info		map;
55 };
56 
armflash_set_vpp(struct map_info * map,int on)57 static void armflash_set_vpp(struct map_info *map, int on)
58 {
59 	struct armflash_info *info = container_of(map, struct armflash_info, map);
60 
61 	if (info->plat && info->plat->set_vpp)
62 		info->plat->set_vpp(on);
63 }
64 
65 static const char *probes[] = { "cmdlinepart", "RedBoot", "afs", NULL };
66 
armflash_probe(struct platform_device * dev)67 static int armflash_probe(struct platform_device *dev)
68 {
69 	struct flash_platform_data *plat = dev->dev.platform_data;
70 	struct resource *res = dev->resource;
71 	unsigned int size = res->end - res->start + 1;
72 	struct armflash_info *info;
73 	int err;
74 	void __iomem *base;
75 
76 	info = kzalloc(sizeof(struct armflash_info), GFP_KERNEL);
77 	if (!info) {
78 		err = -ENOMEM;
79 		goto out;
80 	}
81 
82 	info->plat = plat;
83 	if (plat && plat->init) {
84 		err = plat->init();
85 		if (err)
86 			goto no_resource;
87 	}
88 
89 	info->res = request_mem_region(res->start, size, "armflash");
90 	if (!info->res) {
91 		err = -EBUSY;
92 		goto no_resource;
93 	}
94 
95 	base = ioremap(res->start, size);
96 	if (!base) {
97 		err = -ENOMEM;
98 		goto no_mem;
99 	}
100 
101 	/*
102 	 * look for CFI based flash parts fitted to this board
103 	 */
104 	info->map.size		= size;
105 	info->map.bankwidth	= plat->width;
106 	info->map.phys		= res->start;
107 	info->map.virt		= base;
108 	info->map.name		= dev_name(&dev->dev);
109 	info->map.set_vpp	= armflash_set_vpp;
110 
111 	simple_map_init(&info->map);
112 
113 	/*
114 	 * Also, the CFI layer automatically works out what size
115 	 * of chips we have, and does the necessary identification
116 	 * for us automatically.
117 	 */
118 	info->mtd = do_map_probe(plat->map_name, &info->map);
119 	if (!info->mtd) {
120 		err = -ENXIO;
121 		goto no_device;
122 	}
123 
124 	info->mtd->owner = THIS_MODULE;
125 
126 	err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0);
127 	if (err > 0) {
128 		err = add_mtd_partitions(info->mtd, info->parts, err);
129 		if (err)
130 			printk(KERN_ERR
131 			       "mtd partition registration failed: %d\n", err);
132 	}
133 
134 	if (err == 0)
135 		platform_set_drvdata(dev, info);
136 
137 	/*
138 	 * If we got an error, free all resources.
139 	 */
140 	if (err < 0) {
141 		if (info->mtd) {
142 			del_mtd_partitions(info->mtd);
143 			map_destroy(info->mtd);
144 		}
145 		kfree(info->parts);
146 
147  no_device:
148 		iounmap(base);
149  no_mem:
150 		release_mem_region(res->start, size);
151  no_resource:
152 		if (plat && plat->exit)
153 			plat->exit();
154 		kfree(info);
155 	}
156  out:
157 	return err;
158 }
159 
armflash_remove(struct platform_device * dev)160 static int armflash_remove(struct platform_device *dev)
161 {
162 	struct armflash_info *info = platform_get_drvdata(dev);
163 
164 	platform_set_drvdata(dev, NULL);
165 
166 	if (info) {
167 		if (info->mtd) {
168 			del_mtd_partitions(info->mtd);
169 			map_destroy(info->mtd);
170 		}
171 		kfree(info->parts);
172 
173 		iounmap(info->map.virt);
174 		release_resource(info->res);
175 		kfree(info->res);
176 
177 		if (info->plat && info->plat->exit)
178 			info->plat->exit();
179 
180 		kfree(info);
181 	}
182 
183 	return 0;
184 }
185 
186 static struct platform_driver armflash_driver = {
187 	.probe		= armflash_probe,
188 	.remove		= armflash_remove,
189 	.driver		= {
190 		.name	= "armflash",
191 		.owner	= THIS_MODULE,
192 	},
193 };
194 
armflash_init(void)195 static int __init armflash_init(void)
196 {
197 	return platform_driver_register(&armflash_driver);
198 }
199 
armflash_exit(void)200 static void __exit armflash_exit(void)
201 {
202 	platform_driver_unregister(&armflash_driver);
203 }
204 
205 module_init(armflash_init);
206 module_exit(armflash_exit);
207 
208 MODULE_AUTHOR("ARM Ltd");
209 MODULE_DESCRIPTION("ARM Integrator CFI map driver");
210 MODULE_LICENSE("GPL");
211 MODULE_ALIAS("platform:armflash");
212