diff options
Diffstat (limited to 'drivers/mtd/maps/sun_uflash.c')
-rw-r--r-- | drivers/mtd/maps/sun_uflash.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c new file mode 100644 index 000000000000..29091d10030a --- /dev/null +++ b/drivers/mtd/maps/sun_uflash.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* $Id: sun_uflash.c,v 1.11 2004/11/04 13:24:15 gleixner Exp $ | ||
2 | * | ||
3 | * sun_uflash - Driver implementation for user-programmable flash | ||
4 | * present on many Sun Microsystems SME boardsets. | ||
5 | * | ||
6 | * This driver does NOT provide access to the OBP-flash for | ||
7 | * safety reasons-- use <linux>/drivers/sbus/char/flash.c instead. | ||
8 | * | ||
9 | * Copyright (c) 2001 Eric Brower (ebrower@usa.net) | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/fs.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <asm/ebus.h> | ||
20 | #include <asm/oplib.h> | ||
21 | #include <asm/uaccess.h> | ||
22 | #include <asm/io.h> | ||
23 | |||
24 | #include <linux/mtd/mtd.h> | ||
25 | #include <linux/mtd/map.h> | ||
26 | |||
27 | #define UFLASH_OBPNAME "flashprom" | ||
28 | #define UFLASH_DEVNAME "userflash" | ||
29 | |||
30 | #define UFLASH_WINDOW_SIZE 0x200000 | ||
31 | #define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */ | ||
32 | |||
33 | MODULE_AUTHOR | ||
34 | ("Eric Brower <ebrower@usa.net>"); | ||
35 | MODULE_DESCRIPTION | ||
36 | ("User-programmable flash device on Sun Microsystems boardsets"); | ||
37 | MODULE_SUPPORTED_DEVICE | ||
38 | ("userflash"); | ||
39 | MODULE_LICENSE | ||
40 | ("GPL"); | ||
41 | |||
42 | static LIST_HEAD(device_list); | ||
43 | struct uflash_dev { | ||
44 | char * name; /* device name */ | ||
45 | struct map_info map; /* mtd map info */ | ||
46 | struct mtd_info * mtd; /* mtd info */ | ||
47 | struct list_head list; | ||
48 | }; | ||
49 | |||
50 | |||
51 | struct map_info uflash_map_templ = { | ||
52 | .name = "SUNW,???-????", | ||
53 | .size = UFLASH_WINDOW_SIZE, | ||
54 | .bankwidth = UFLASH_BUSWIDTH, | ||
55 | }; | ||
56 | |||
57 | int uflash_devinit(struct linux_ebus_device* edev) | ||
58 | { | ||
59 | int iTmp, nregs; | ||
60 | struct linux_prom_registers regs[2]; | ||
61 | struct uflash_dev *pdev; | ||
62 | |||
63 | iTmp = prom_getproperty( | ||
64 | edev->prom_node, "reg", (void *)regs, sizeof(regs)); | ||
65 | if ((iTmp % sizeof(regs[0])) != 0) { | ||
66 | printk("%s: Strange reg property size %d\n", | ||
67 | UFLASH_DEVNAME, iTmp); | ||
68 | return -ENODEV; | ||
69 | } | ||
70 | |||
71 | nregs = iTmp / sizeof(regs[0]); | ||
72 | |||
73 | if (nregs != 1) { | ||
74 | /* Non-CFI userflash device-- once I find one we | ||
75 | * can work on supporting it. | ||
76 | */ | ||
77 | printk("%s: unsupported device at 0x%lx (%d regs): " \ | ||
78 | "email ebrower@usa.net\n", | ||
79 | UFLASH_DEVNAME, edev->resource[0].start, nregs); | ||
80 | return -ENODEV; | ||
81 | } | ||
82 | |||
83 | if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) { | ||
84 | printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME); | ||
85 | return(-ENOMEM); | ||
86 | } | ||
87 | |||
88 | /* copy defaults and tweak parameters */ | ||
89 | memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ)); | ||
90 | pdev->map.size = regs[0].reg_size; | ||
91 | |||
92 | iTmp = prom_getproplen(edev->prom_node, "model"); | ||
93 | pdev->name = kmalloc(iTmp, GFP_KERNEL); | ||
94 | prom_getstring(edev->prom_node, "model", pdev->name, iTmp); | ||
95 | if(0 != pdev->name && 0 < strlen(pdev->name)) { | ||
96 | pdev->map.name = pdev->name; | ||
97 | } | ||
98 | pdev->map.phys = edev->resource[0].start; | ||
99 | pdev->map.virt = ioremap_nocache(edev->resource[0].start, pdev->map.size); | ||
100 | if(0 == pdev->map.virt) { | ||
101 | printk("%s: failed to map device\n", __FUNCTION__); | ||
102 | kfree(pdev->name); | ||
103 | kfree(pdev); | ||
104 | return(-1); | ||
105 | } | ||
106 | |||
107 | simple_map_init(&pdev->map); | ||
108 | |||
109 | /* MTD registration */ | ||
110 | pdev->mtd = do_map_probe("cfi_probe", &pdev->map); | ||
111 | if(0 == pdev->mtd) { | ||
112 | iounmap(pdev->map.virt); | ||
113 | kfree(pdev->name); | ||
114 | kfree(pdev); | ||
115 | return(-ENXIO); | ||
116 | } | ||
117 | |||
118 | list_add(&pdev->list, &device_list); | ||
119 | |||
120 | pdev->mtd->owner = THIS_MODULE; | ||
121 | |||
122 | add_mtd_device(pdev->mtd); | ||
123 | return(0); | ||
124 | } | ||
125 | |||
126 | static int __init uflash_init(void) | ||
127 | { | ||
128 | struct linux_ebus *ebus = NULL; | ||
129 | struct linux_ebus_device *edev = NULL; | ||
130 | |||
131 | for_each_ebus(ebus) { | ||
132 | for_each_ebusdev(edev, ebus) { | ||
133 | if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) { | ||
134 | if(0 > prom_getproplen(edev->prom_node, "user")) { | ||
135 | DEBUG(2, "%s: ignoring device at 0x%lx\n", | ||
136 | UFLASH_DEVNAME, edev->resource[0].start); | ||
137 | } else { | ||
138 | uflash_devinit(edev); | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
144 | if(list_empty(&device_list)) { | ||
145 | printk("%s: unable to locate device\n", UFLASH_DEVNAME); | ||
146 | return -ENODEV; | ||
147 | } | ||
148 | return(0); | ||
149 | } | ||
150 | |||
151 | static void __exit uflash_cleanup(void) | ||
152 | { | ||
153 | struct list_head *udevlist; | ||
154 | struct uflash_dev *udev; | ||
155 | |||
156 | list_for_each(udevlist, &device_list) { | ||
157 | udev = list_entry(udevlist, struct uflash_dev, list); | ||
158 | DEBUG(2, "%s: removing device %s\n", | ||
159 | UFLASH_DEVNAME, udev->name); | ||
160 | |||
161 | if(0 != udev->mtd) { | ||
162 | del_mtd_device(udev->mtd); | ||
163 | map_destroy(udev->mtd); | ||
164 | } | ||
165 | if(0 != udev->map.virt) { | ||
166 | iounmap(udev->map.virt); | ||
167 | udev->map.virt = NULL; | ||
168 | } | ||
169 | if(0 != udev->name) { | ||
170 | kfree(udev->name); | ||
171 | } | ||
172 | kfree(udev); | ||
173 | } | ||
174 | } | ||
175 | |||
176 | module_init(uflash_init); | ||
177 | module_exit(uflash_cleanup); | ||