GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / mtd / bcm947xx / devices / bcmsflash.c
blob3d2ce6013c8e8332dbac847af9fff73cc554f4d0
1 /*
2 * Broadcom SiliconBackplane chipcommon serial flash interface
4 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 * $Id$
21 #include <linux/version.h>
23 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
24 #include <linux/config.h>
25 #endif
26 #include <linux/module.h>
27 #include <linux/slab.h>
28 #include <linux/ioport.h>
29 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)
30 #include <linux/mtd/compatmac.h>
31 #endif
32 #include <linux/mtd/mtd.h>
33 #include <linux/mtd/partitions.h>
34 #include <linux/errno.h>
35 #include <linux/pci.h>
36 #include <linux/delay.h>
37 #include <asm/io.h>
39 #include <typedefs.h>
40 #include <osl.h>
41 #include <bcmutils.h>
42 #include <bcmdevs.h>
43 #include <bcmnvram.h>
44 #include <siutils.h>
45 #include <hndpci.h>
46 #include <pcicfg.h>
47 #include <hndsoc.h>
48 #include <hndsflash.h>
51 #ifdef CONFIG_MTD_PARTITIONS
52 extern struct mtd_partition *
53 init_mtd_partitions(hndsflash_t *sfl, struct mtd_info *mtd, size_t size);
54 #endif
56 extern void *partitions_lock_init(void);
57 #define BCMSFLASH_LOCK(lock) if (lock) spin_lock(lock)
58 #define BCMSFLASH_UNLOCK(lock) if (lock) spin_unlock(lock)
60 struct bcmsflash_mtd {
61 si_t *sih;
62 hndsflash_t *sfl;
63 struct mtd_info mtd;
64 struct mtd_erase_region_info region;
67 /* Private global state */
68 static struct bcmsflash_mtd bcmsflash;
70 static int
71 bcmsflash_mtd_poll(hndsflash_t *sfl, unsigned int offset, int timeout)
73 int now = jiffies;
74 int ret = 0;
76 for (;;) {
77 if (!hndsflash_poll(sfl, offset))
78 break;
80 if (time_after((unsigned long)jiffies, (unsigned long)now + timeout)) {
81 if (!hndsflash_poll(sfl, offset))
82 break;
84 printk(KERN_ERR "sflash: timeout\n");
85 ret = -ETIMEDOUT;
86 break;
88 udelay(1);
91 return ret;
94 static int
95 bcmsflash_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
97 hndsflash_t *sfl = ((struct bcmsflash_mtd *)mtd->priv)->sfl;
98 int bytes, ret = 0;
100 /* Check address range */
101 if (!len)
102 return 0;
103 if ((from + len) > mtd->size)
104 return -EINVAL;
106 BCMSFLASH_LOCK(mtd->mlock);
108 *retlen = 0;
109 while (len) {
110 if ((bytes = hndsflash_read(sfl, (uint)from, len, buf))
111 < 0) {
112 ret = bytes;
113 break;
115 from += (loff_t) bytes;
116 len -= bytes;
117 buf += bytes;
118 *retlen += bytes;
121 BCMSFLASH_UNLOCK(mtd->mlock);
122 return ret;
125 static int
126 bcmsflash_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
128 hndsflash_t *sfl = ((struct bcmsflash_mtd *)mtd->priv)->sfl;
129 int bytes, ret = 0;
131 /* Check address range */
132 if (!len)
133 return 0;
134 if ((to + len) > mtd->size)
135 return -EINVAL;
137 BCMSFLASH_LOCK(mtd->mlock);
138 *retlen = 0;
139 while (len) {
140 if ((bytes = hndsflash_write(sfl, (uint)to, len, (u_char *)buf))
141 < 0) {
142 ret = bytes;
143 break;
145 if ((ret = bcmsflash_mtd_poll(sfl, (unsigned int)to, HZ)))
146 break;
147 to += (loff_t) bytes;
148 len -= bytes;
149 buf += bytes;
150 *retlen += bytes;
153 BCMSFLASH_UNLOCK(mtd->mlock);
154 return ret;
157 static int
158 bcmsflash_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
160 hndsflash_t *sfl = ((struct bcmsflash_mtd *)mtd->priv)->sfl;
161 int i, j, ret = 0;
162 unsigned int addr, len;
164 /* Check address range */
165 if (!erase->len)
166 return 0;
167 if ((erase->addr + erase->len) > mtd->size)
168 return -EINVAL;
170 BCMSFLASH_LOCK(mtd->mlock);
171 addr = erase->addr;
172 len = erase->len;
174 /* Ensure that requested region is aligned */
175 for (i = 0; i < mtd->numeraseregions; i++) {
176 for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
177 if (addr == mtd->eraseregions[i].offset +
178 mtd->eraseregions[i].erasesize * j &&
179 len >= mtd->eraseregions[i].erasesize) {
180 if ((ret = hndsflash_erase(sfl, addr)) < 0)
181 break;
182 if ((ret = bcmsflash_mtd_poll(sfl, addr, 10 * HZ)))
183 break;
184 addr += mtd->eraseregions[i].erasesize;
185 len -= mtd->eraseregions[i].erasesize;
188 if (ret)
189 break;
192 /* Set erase status */
193 if (ret < 0)
194 erase->state = MTD_ERASE_FAILED;
195 else {
196 erase->state = MTD_ERASE_DONE;
197 ret = 0;
200 BCMSFLASH_UNLOCK(mtd->mlock);
202 /* Call erase callback */
203 if (erase->callback)
204 erase->callback(erase);
206 return ret;
209 static int __init
210 bcmsflash_mtd_init(void)
212 int ret = 0;
213 hndsflash_t *info;
214 #ifdef CONFIG_MTD_PARTITIONS
215 struct mtd_partition *parts;
216 int i;
217 #endif
219 memset(&bcmsflash, 0, sizeof(struct bcmsflash_mtd));
221 /* attach to the backplane */
222 if (!(bcmsflash.sih = si_kattach(SI_OSH))) {
223 printk(KERN_ERR "bcmsflash: error attaching to backplane\n");
224 ret = -EIO;
225 goto fail;
228 /* Initialize serial flash access */
229 if (!(info = hndsflash_init(bcmsflash.sih))) {
230 printk(KERN_ERR "bcmsflash: found no supported devices\n");
231 ret = -ENODEV;
232 goto fail;
234 bcmsflash.sfl = info;
236 /* Setup region info */
237 bcmsflash.region.offset = 0;
238 bcmsflash.region.erasesize = info->blocksize;
239 bcmsflash.region.numblocks = info->numblocks;
240 if (bcmsflash.region.erasesize > bcmsflash.mtd.erasesize)
241 bcmsflash.mtd.erasesize = bcmsflash.region.erasesize;
242 bcmsflash.mtd.size = info->size;
243 bcmsflash.mtd.numeraseregions = 1;
245 /* Register with MTD */
246 bcmsflash.mtd.name = "bcmsflash";
247 bcmsflash.mtd.type = MTD_NORFLASH;
248 bcmsflash.mtd.flags = MTD_CAP_NORFLASH;
249 bcmsflash.mtd.eraseregions = &bcmsflash.region;
250 bcmsflash.mtd.erase = bcmsflash_mtd_erase;
251 bcmsflash.mtd.read = bcmsflash_mtd_read;
252 bcmsflash.mtd.write = bcmsflash_mtd_write;
253 bcmsflash.mtd.writesize = 1;
254 bcmsflash.mtd.priv = &bcmsflash;
255 bcmsflash.mtd.owner = THIS_MODULE;
256 bcmsflash.mtd.mlock = partitions_lock_init();
257 if (!bcmsflash.mtd.mlock)
258 return -ENOMEM;
260 #ifdef CONFIG_MTD_PARTITIONS
261 parts = init_mtd_partitions(info, &bcmsflash.mtd, bcmsflash.mtd.size);
262 if (parts) {
263 for (i = 0; parts[i].name; i++);
264 ret = add_mtd_partitions(&bcmsflash.mtd, parts, i);
265 if (ret) {
266 printk(KERN_ERR "bcmsflash: add_mtd failed\n");
267 goto fail;
270 #endif
272 return 0;
274 fail:
275 return ret;
278 static void __exit
279 bcmsflash_mtd_exit(void)
281 #ifdef CONFIG_MTD_PARTITIONS
282 del_mtd_partitions(&bcmsflash.mtd);
283 #else
284 del_mtd_device(&bcmsflash.mtd);
285 #endif
288 module_init(bcmsflash_mtd_init);
289 module_exit(bcmsflash_mtd_exit);