plat-ram.c 6.3 KB
Newer Older
B
Ben Dooks 已提交
1 2 3 4 5 6 7 8
/* drivers/mtd/maps/plat-ram.c
 *
 * (c) 2004-2005 Simtec Electronics
 *	http://www.simtec.co.uk/products/SWLINUX/
 *	Ben Dooks <ben@simtec.co.uk>
 *
 * Generic platfrom device based RAM map
 *
9
 * $Id: plat-ram.c,v 1.7 2005/11/07 11:14:28 gleixner Exp $
B
Ben Dooks 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/device.h>
T
Tim Schmielau 已提交
33
#include <linux/slab.h>
34
#include <linux/platform_device.h>
B
Ben Dooks 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/plat-ram.h>

#include <asm/io.h>

/* private structure for each mtd platform ram device created */

struct platram_info {
	struct device		*dev;
	struct mtd_info		*mtd;
	struct map_info		 map;
	struct mtd_partition	*partitions;
	struct resource		*area;
	struct platdata_mtd_ram	*pdata;
};

/* to_platram_info()
 *
 * device private data to struct platram_info conversion
*/

59
static inline struct platram_info *to_platram_info(struct platform_device *dev)
B
Ben Dooks 已提交
60
{
61
	return (struct platram_info *)platform_get_drvdata(dev);
B
Ben Dooks 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
}

/* platram_setrw
 *
 * call the platform device's set rw/ro control
 *
 * to = 0 => read-only
 *    = 1 => read-write
*/

static inline void platram_setrw(struct platram_info *info, int to)
{
	if (info->pdata == NULL)
		return;

	if (info->pdata->set_rw != NULL)
		(info->pdata->set_rw)(info->dev, to);
}

/* platram_remove
 *
 * called to remove the device from the driver's control
*/

86
static int platram_remove(struct platform_device *pdev)
B
Ben Dooks 已提交
87
{
88
	struct platram_info *info = to_platram_info(pdev);
B
Ben Dooks 已提交
89

90
	platform_set_drvdata(pdev, NULL);
B
Ben Dooks 已提交
91

92
	dev_dbg(&pdev->dev, "removing device\n");
B
Ben Dooks 已提交
93

94
	if (info == NULL)
B
Ben Dooks 已提交
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
		return 0;

	if (info->mtd) {
#ifdef CONFIG_MTD_PARTITIONS
		if (info->partitions) {
			del_mtd_partitions(info->mtd);
			kfree(info->partitions);
		}
#endif
		del_mtd_device(info->mtd);
		map_destroy(info->mtd);
	}

	/* ensure ram is left read-only */

	platram_setrw(info, PLATRAM_RO);

	/* release resources */

	if (info->area) {
		release_resource(info->area);
		kfree(info->area);
	}

	if (info->map.virt != NULL)
		iounmap(info->map.virt);
121

B
Ben Dooks 已提交
122 123 124 125 126 127 128 129 130 131 132
	kfree(info);

	return 0;
}

/* platram_probe
 *
 * called from device drive system when a device matching our
 * driver is found.
*/

133
static int platram_probe(struct platform_device *pdev)
B
Ben Dooks 已提交
134 135 136 137 138 139
{
	struct platdata_mtd_ram	*pdata;
	struct platram_info *info;
	struct resource *res;
	int err = 0;

140
	dev_dbg(&pdev->dev, "probe entered\n");
141

142 143
	if (pdev->dev.platform_data == NULL) {
		dev_err(&pdev->dev, "no platform data supplied\n");
B
Ben Dooks 已提交
144 145 146 147
		err = -ENOENT;
		goto exit_error;
	}

148
	pdata = pdev->dev.platform_data;
B
Ben Dooks 已提交
149

150
	info = kzalloc(sizeof(*info), GFP_KERNEL);
B
Ben Dooks 已提交
151
	if (info == NULL) {
152
		dev_err(&pdev->dev, "no memory for flash info\n");
B
Ben Dooks 已提交
153 154 155 156
		err = -ENOMEM;
		goto exit_error;
	}

157
	platform_set_drvdata(pdev, info);
B
Ben Dooks 已提交
158

159
	info->dev = &pdev->dev;
B
Ben Dooks 已提交
160 161 162 163
	info->pdata = pdata;

	/* get the resource for the memory mapping */

164
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
B
Ben Dooks 已提交
165 166

	if (res == NULL) {
167
		dev_err(&pdev->dev, "no memory resource specified\n");
B
Ben Dooks 已提交
168 169 170 171
		err = -ENOENT;
		goto exit_free;
	}

172 173
	dev_dbg(&pdev->dev, "got platform resource %p (0x%llx)\n", res,
		(unsigned long long)res->start);
B
Ben Dooks 已提交
174 175 176 177 178

	/* setup map parameters */

	info->map.phys = res->start;
	info->map.size = (res->end - res->start) + 1;
179
	info->map.name = pdata->mapname != NULL ? pdata->mapname : (char *)pdev->name;
B
Ben Dooks 已提交
180 181 182 183
	info->map.bankwidth = pdata->bankwidth;

	/* register our usage of the memory area */

184
	info->area = request_mem_region(res->start, info->map.size, pdev->name);
B
Ben Dooks 已提交
185
	if (info->area == NULL) {
186
		dev_err(&pdev->dev, "failed to request memory region\n");
B
Ben Dooks 已提交
187 188 189 190 191 192 193
		err = -EIO;
		goto exit_free;
	}

	/* remap the memory area */

	info->map.virt = ioremap(res->start, info->map.size);
194
	dev_dbg(&pdev->dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size);
B
Ben Dooks 已提交
195 196

	if (info->map.virt == NULL) {
197
		dev_err(&pdev->dev, "failed to ioremap() region\n");
B
Ben Dooks 已提交
198 199 200 201 202 203
		err = -EIO;
		goto exit_free;
	}

	simple_map_init(&info->map);

204
	dev_dbg(&pdev->dev, "initialised map, probing for mtd\n");
B
Ben Dooks 已提交
205 206 207 208 209

	/* probe for the right mtd map driver */

	info->mtd = do_map_probe("map_ram" , &info->map);
	if (info->mtd == NULL) {
210
		dev_err(&pdev->dev, "failed to probe for map_ram\n");
B
Ben Dooks 已提交
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
		err = -ENOMEM;
		goto exit_free;
	}

	info->mtd->owner = THIS_MODULE;

	platram_setrw(info, PLATRAM_RW);

	/* check to see if there are any available partitions, or wether
	 * to add this device whole */

#ifdef CONFIG_MTD_PARTITIONS
	if (pdata->nr_partitions > 0) {
		const char **probes = { NULL };

		if (pdata->probes)
			probes = (const char **)pdata->probes;

		err = parse_mtd_partitions(info->mtd, probes,
					   &info->partitions, 0);
		if (err > 0) {
			err = add_mtd_partitions(info->mtd, info->partitions,
						 err);
		}
	}
#endif /* CONFIG_MTD_PARTITIONS */

	if (add_mtd_device(info->mtd)) {
239
		dev_err(&pdev->dev, "add_mtd_device() failed\n");
B
Ben Dooks 已提交
240 241
		err = -ENOMEM;
	}
242

243
	dev_info(&pdev->dev, "registered mtd device\n");
B
Ben Dooks 已提交
244 245 246
	return err;

 exit_free:
247
	platram_remove(pdev);
B
Ben Dooks 已提交
248 249 250 251 252 253
 exit_error:
	return err;
}

/* device driver info */

254
static struct platform_driver platram_driver = {
B
Ben Dooks 已提交
255 256
	.probe		= platram_probe,
	.remove		= platram_remove,
257 258 259 260
	.driver		= {
		.name	= "mtd-ram",
		.owner	= THIS_MODULE,
	},
B
Ben Dooks 已提交
261 262 263 264 265 266 267
};

/* module init/exit */

static int __init platram_init(void)
{
	printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
268
	return platform_driver_register(&platram_driver);
B
Ben Dooks 已提交
269 270 271 272
}

static void __exit platram_exit(void)
{
273
	platform_driver_unregister(&platram_driver);
B
Ben Dooks 已提交
274 275 276 277 278 279 280 281
}

module_init(platram_init);
module_exit(platram_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
MODULE_DESCRIPTION("MTD platform RAM map driver");