more debug output
[linux-2.4.git] / drivers / mtd / maps / sun_uflash.c
1 /* $Id: sun_uflash.c,v 1.4 2001/10/02 15:05:14 dwmw2 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/version.h>
16 #include <linux/fs.h>
17 #include <linux/errno.h>
18 #include <linux/init.h>
19 #include <linux/ioport.h>
20 #include <asm/ebus.h>
21 #include <asm/oplib.h>
22 #include <asm/uaccess.h>
23 #include <asm/io.h>
24
25 #include <linux/mtd/mtd.h>
26 #include <linux/mtd/map.h>
27
28 #define UFLASH_OBPNAME  "flashprom"
29 #define UFLASH_DEVNAME  "userflash"
30
31 #define UFLASH_WINDOW_SIZE      0x200000
32 #define UFLASH_BUSWIDTH         1                       /* EBus is 8-bit */
33
34 MODULE_AUTHOR
35         ("Eric Brower <ebrower@usa.net>");
36 MODULE_DESCRIPTION
37         ("User-programmable flash device on Sun Microsystems boardsets");
38 MODULE_SUPPORTED_DEVICE
39         ("userflash");
40 MODULE_LICENSE
41         ("GPL");
42
43 static LIST_HEAD(device_list);
44 struct uflash_dev {
45         char *                  name;   /* device name */
46         struct map_info         map;    /* mtd map info */
47         struct mtd_info *       mtd;    /* mtd info */
48         struct list_head        list;
49 };
50
51 __u8 uflash_read8(struct map_info *map, unsigned long ofs)
52 {
53         return(__raw_readb(map->map_priv_1 + ofs));
54 }
55
56 __u16 uflash_read16(struct map_info *map, unsigned long ofs)
57 {
58         return(__raw_readw(map->map_priv_1 + ofs));
59 }
60
61 __u32 uflash_read32(struct map_info *map, unsigned long ofs)
62 {
63         return(__raw_readl(map->map_priv_1 + ofs));
64 }
65
66 void uflash_copy_from(struct map_info *map, void *to, unsigned long from, 
67                       ssize_t len)
68 {
69         memcpy_fromio(to, map->map_priv_1 + from, len);
70 }
71
72 void uflash_write8(struct map_info *map, __u8 d, unsigned long adr)
73 {
74         __raw_writeb(d, map->map_priv_1 + adr);
75 }
76
77 void uflash_write16(struct map_info *map, __u16 d, unsigned long adr)
78 {
79         __raw_writew(d, map->map_priv_1 + adr);
80 }
81
82 void uflash_write32(struct map_info *map, __u32 d, unsigned long adr)
83 {
84         __raw_writel(d, map->map_priv_1 + adr);
85 }
86
87 void uflash_copy_to(struct map_info *map, unsigned long to, const void *from,
88                     ssize_t len)
89 {
90         memcpy_toio(map->map_priv_1 + to, from, len);
91 }
92
93 struct map_info uflash_map_templ = {
94                 name:           "SUNW,???-????",
95                 size:           UFLASH_WINDOW_SIZE,
96                 buswidth:       UFLASH_BUSWIDTH,
97                 read8:          uflash_read8,
98                 read16:         uflash_read16,
99                 read32:         uflash_read32,
100                 copy_from:      uflash_copy_from,
101                 write8:         uflash_write8,
102                 write16:        uflash_write16,
103                 write32:        uflash_write32,
104                 copy_to:        uflash_copy_to
105 };
106
107 int uflash_devinit(struct linux_ebus_device* edev)
108 {
109         int iTmp, nregs;
110         struct linux_prom_registers regs[2];
111         struct uflash_dev *pdev;
112
113         iTmp = prom_getproperty(
114                 edev->prom_node, "reg", (void *)regs, sizeof(regs));
115         if ((iTmp % sizeof(regs[0])) != 0) {
116                 printk("%s: Strange reg property size %d\n", 
117                         UFLASH_DEVNAME, iTmp);
118                 return -ENODEV;
119         }
120
121         nregs = iTmp / sizeof(regs[0]);
122
123         if (nregs != 1) {
124                 /* Non-CFI userflash device-- once I find one we
125                  * can work on supporting it.
126                  */
127                 printk("%s: unsupported device at 0x%lx (%d regs): " \
128                         "email ebrower@usa.net\n", 
129                         UFLASH_DEVNAME, edev->resource[0].start, nregs);
130                 return -ENODEV;
131         }
132
133         if(0 == (pdev = kmalloc(sizeof(struct uflash_dev), GFP_KERNEL))) {
134                 printk("%s: unable to kmalloc new device\n", UFLASH_DEVNAME);
135                 return(-ENOMEM);
136         }
137         
138         /* copy defaults and tweak parameters */
139         memcpy(&pdev->map, &uflash_map_templ, sizeof(uflash_map_templ));
140         pdev->map.size = regs[0].reg_size;
141
142         iTmp = prom_getproplen(edev->prom_node, "model");
143         pdev->name = kmalloc(iTmp, GFP_KERNEL);
144         prom_getstring(edev->prom_node, "model", pdev->name, iTmp);
145         if(0 != pdev->name && 0 < strlen(pdev->name)) {
146                 pdev->map.name = pdev->name;
147         }
148
149         pdev->map.map_priv_1 = 
150                 (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size);
151         if(0 == pdev->map.map_priv_1) {
152                 printk("%s: failed to map device\n", __FUNCTION__);
153                 kfree(pdev->name);
154                 kfree(pdev);
155                 return(-1);
156         }
157
158         /* MTD registration */
159         pdev->mtd = do_map_probe("cfi_probe", &pdev->map);
160         if(0 == pdev->mtd) {
161                 iounmap((void *)pdev->map.map_priv_1);
162                 kfree(pdev->name);
163                 kfree(pdev);
164                 return(-ENXIO);
165         }
166
167         list_add(&pdev->list, &device_list);
168
169         pdev->mtd->module = THIS_MODULE;
170
171         add_mtd_device(pdev->mtd);
172         return(0);
173 }
174
175 static int __init uflash_init(void)
176 {
177         struct linux_ebus *ebus = NULL;
178         struct linux_ebus_device *edev = NULL;
179
180         for_each_ebus(ebus) {
181                 for_each_ebusdev(edev, ebus) {
182                         if (!strcmp(edev->prom_name, UFLASH_OBPNAME)) {
183                                 if(0 > prom_getproplen(edev->prom_node, "user")) {
184                                         DEBUG(2, "%s: ignoring device at 0x%lx\n",
185                                                         UFLASH_DEVNAME, edev->resource[0].start);
186                                 } else {
187                                         uflash_devinit(edev);
188                                 }
189                         }
190                 }
191         }
192
193         if(list_empty(&device_list)) {
194                 printk("%s: unable to locate device\n", UFLASH_DEVNAME);
195                 return -ENODEV;
196         }
197         return(0);
198 }
199
200 static void __exit uflash_cleanup(void)
201 {
202         struct list_head *udevlist;
203         struct uflash_dev *udev;
204
205         list_for_each(udevlist, &device_list) {
206                 udev = list_entry(udevlist, struct uflash_dev, list);
207                 DEBUG(2, "%s: removing device %s\n", 
208                         UFLASH_DEVNAME, udev->name);
209
210                 if(0 != udev->mtd) {
211                         del_mtd_device(udev->mtd);
212                         map_destroy(udev->mtd);
213                 }
214                 if(0 != udev->map.map_priv_1) {
215                         iounmap((void*)udev->map.map_priv_1);
216                         udev->map.map_priv_1 = 0;
217                 }
218                 if(0 != udev->name) {
219                         kfree(udev->name);
220                 }
221                 kfree(udev);
222         }       
223 }
224
225 module_init(uflash_init);
226 module_exit(uflash_cleanup);