OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [mtd/] [devices/] [mtd_dataflash.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Atmel AT45xxx DataFlash MTD driver for lightweight SPI framework
3
 *
4
 * Largely derived from at91_dataflash.c:
5
 *  Copyright (C) 2003-2005 SAN People (Pty) Ltd
6
 *
7
 * This program is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU General Public License
9
 * as published by the Free Software Foundation; either version
10
 * 2 of the License, or (at your option) any later version.
11
*/
12
#include <linux/module.h>
13
#include <linux/init.h>
14
#include <linux/slab.h>
15
#include <linux/delay.h>
16
#include <linux/device.h>
17
#include <linux/mutex.h>
18
#include <linux/spi/spi.h>
19
#include <linux/spi/flash.h>
20
 
21
#include <linux/mtd/mtd.h>
22
#include <linux/mtd/partitions.h>
23
 
24
 
25
/*
26
 * DataFlash is a kind of SPI flash.  Most AT45 chips have two buffers in
27
 * each chip, which may be used for double buffered I/O; but this driver
28
 * doesn't (yet) use these for any kind of i/o overlap or prefetching.
29
 *
30
 * Sometimes DataFlash is packaged in MMC-format cards, although the
31
 * MMC stack can't use SPI (yet), or distinguish between MMC and DataFlash
32
 * protocols during enumeration.
33
 */
34
 
35
#define CONFIG_DATAFLASH_WRITE_VERIFY
36
 
37
/* reads can bypass the buffers */
38
#define OP_READ_CONTINUOUS      0xE8
39
#define OP_READ_PAGE            0xD2
40
 
41
/* group B requests can run even while status reports "busy" */
42
#define OP_READ_STATUS          0xD7    /* group B */
43
 
44
/* move data between host and buffer */
45
#define OP_READ_BUFFER1         0xD4    /* group B */
46
#define OP_READ_BUFFER2         0xD6    /* group B */
47
#define OP_WRITE_BUFFER1        0x84    /* group B */
48
#define OP_WRITE_BUFFER2        0x87    /* group B */
49
 
50
/* erasing flash */
51
#define OP_ERASE_PAGE           0x81
52
#define OP_ERASE_BLOCK          0x50
53
 
54
/* move data between buffer and flash */
55
#define OP_TRANSFER_BUF1        0x53
56
#define OP_TRANSFER_BUF2        0x55
57
#define OP_MREAD_BUFFER1        0xD4
58
#define OP_MREAD_BUFFER2        0xD6
59
#define OP_MWERASE_BUFFER1      0x83
60
#define OP_MWERASE_BUFFER2      0x86
61
#define OP_MWRITE_BUFFER1       0x88    /* sector must be pre-erased */
62
#define OP_MWRITE_BUFFER2       0x89    /* sector must be pre-erased */
63
 
64
/* write to buffer, then write-erase to flash */
65
#define OP_PROGRAM_VIA_BUF1     0x82
66
#define OP_PROGRAM_VIA_BUF2     0x85
67
 
68
/* compare buffer to flash */
69
#define OP_COMPARE_BUF1         0x60
70
#define OP_COMPARE_BUF2         0x61
71
 
72
/* read flash to buffer, then write-erase to flash */
73
#define OP_REWRITE_VIA_BUF1     0x58
74
#define OP_REWRITE_VIA_BUF2     0x59
75
 
76
/* newer chips report JEDEC manufacturer and device IDs; chip
77
 * serial number and OTP bits; and per-sector writeprotect.
78
 */
79
#define OP_READ_ID              0x9F
80
#define OP_READ_SECURITY        0x77
81
#define OP_WRITE_SECURITY       0x9A    /* OTP bits */
82
 
83
 
84
struct dataflash {
85
        u8                      command[4];
86
        char                    name[24];
87
 
88
        unsigned                partitioned:1;
89
 
90
        unsigned short          page_offset;    /* offset in flash address */
91
        unsigned int            page_size;      /* of bytes per page */
92
 
93
        struct mutex            lock;
94
        struct spi_device       *spi;
95
 
96
        struct mtd_info         mtd;
97
};
98
 
99
#ifdef CONFIG_MTD_PARTITIONS
100
#define mtd_has_partitions()    (1)
101
#else
102
#define mtd_has_partitions()    (0)
103
#endif
104
 
105
/* ......................................................................... */
106
 
107
/*
108
 * Return the status of the DataFlash device.
109
 */
110
static inline int dataflash_status(struct spi_device *spi)
111
{
112
        /* NOTE:  at45db321c over 25 MHz wants to write
113
         * a dummy byte after the opcode...
114
         */
115
        return spi_w8r8(spi, OP_READ_STATUS);
116
}
117
 
118
/*
119
 * Poll the DataFlash device until it is READY.
120
 * This usually takes 5-20 msec or so; more for sector erase.
121
 */
122
static int dataflash_waitready(struct spi_device *spi)
123
{
124
        int     status;
125
 
126
        for (;;) {
127
                status = dataflash_status(spi);
128
                if (status < 0) {
129
                        DEBUG(MTD_DEBUG_LEVEL1, "%s: status %d?\n",
130
                                        spi->dev.bus_id, status);
131
                        status = 0;
132
                }
133
 
134
                if (status & (1 << 7))  /* RDY/nBSY */
135
                        return status;
136
 
137
                msleep(3);
138
        }
139
}
140
 
141
/* ......................................................................... */
142
 
143
/*
144
 * Erase pages of flash.
145
 */
146
static int dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
147
{
148
        struct dataflash        *priv = (struct dataflash *)mtd->priv;
149
        struct spi_device       *spi = priv->spi;
150
        struct spi_transfer     x = { .tx_dma = 0, };
151
        struct spi_message      msg;
152
        unsigned                blocksize = priv->page_size << 3;
153
        u8                      *command;
154
 
155
        DEBUG(MTD_DEBUG_LEVEL2, "%s: erase addr=0x%x len 0x%x\n",
156
                        spi->dev.bus_id,
157
                        instr->addr, instr->len);
158
 
159
        /* Sanity checks */
160
        if ((instr->addr + instr->len) > mtd->size
161
                        || (instr->len % priv->page_size) != 0
162
                        || (instr->addr % priv->page_size) != 0)
163
                return -EINVAL;
164
 
165
        spi_message_init(&msg);
166
 
167
        x.tx_buf = command = priv->command;
168
        x.len = 4;
169
        spi_message_add_tail(&x, &msg);
170
 
171
        mutex_lock(&priv->lock);
172
        while (instr->len > 0) {
173
                unsigned int    pageaddr;
174
                int             status;
175
                int             do_block;
176
 
177
                /* Calculate flash page address; use block erase (for speed) if
178
                 * we're at a block boundary and need to erase the whole block.
179
                 */
180
                pageaddr = instr->addr / priv->page_size;
181
                do_block = (pageaddr & 0x7) == 0 && instr->len >= blocksize;
182
                pageaddr = pageaddr << priv->page_offset;
183
 
184
                command[0] = do_block ? OP_ERASE_BLOCK : OP_ERASE_PAGE;
185
                command[1] = (u8)(pageaddr >> 16);
186
                command[2] = (u8)(pageaddr >> 8);
187
                command[3] = 0;
188
 
189
                DEBUG(MTD_DEBUG_LEVEL3, "ERASE %s: (%x) %x %x %x [%i]\n",
190
                        do_block ? "block" : "page",
191
                        command[0], command[1], command[2], command[3],
192
                        pageaddr);
193
 
194
                status = spi_sync(spi, &msg);
195
                (void) dataflash_waitready(spi);
196
 
197
                if (status < 0) {
198
                        printk(KERN_ERR "%s: erase %x, err %d\n",
199
                                spi->dev.bus_id, pageaddr, status);
200
                        /* REVISIT:  can retry instr->retries times; or
201
                         * giveup and instr->fail_addr = instr->addr;
202
                         */
203
                        continue;
204
                }
205
 
206
                if (do_block) {
207
                        instr->addr += blocksize;
208
                        instr->len -= blocksize;
209
                } else {
210
                        instr->addr += priv->page_size;
211
                        instr->len -= priv->page_size;
212
                }
213
        }
214
        mutex_unlock(&priv->lock);
215
 
216
        /* Inform MTD subsystem that erase is complete */
217
        instr->state = MTD_ERASE_DONE;
218
        mtd_erase_callback(instr);
219
 
220
        return 0;
221
}
222
 
223
/*
224
 * Read from the DataFlash device.
225
 *   from   : Start offset in flash device
226
 *   len    : Amount to read
227
 *   retlen : About of data actually read
228
 *   buf    : Buffer containing the data
229
 */
230
static int dataflash_read(struct mtd_info *mtd, loff_t from, size_t len,
231
                               size_t *retlen, u_char *buf)
232
{
233
        struct dataflash        *priv = (struct dataflash *)mtd->priv;
234
        struct spi_transfer     x[2] = { { .tx_dma = 0, }, };
235
        struct spi_message      msg;
236
        unsigned int            addr;
237
        u8                      *command;
238
        int                     status;
239
 
240
        DEBUG(MTD_DEBUG_LEVEL2, "%s: read 0x%x..0x%x\n",
241
                priv->spi->dev.bus_id, (unsigned)from, (unsigned)(from + len));
242
 
243
        *retlen = 0;
244
 
245
        /* Sanity checks */
246
        if (!len)
247
                return 0;
248
        if (from + len > mtd->size)
249
                return -EINVAL;
250
 
251
        /* Calculate flash page/byte address */
252
        addr = (((unsigned)from / priv->page_size) << priv->page_offset)
253
                + ((unsigned)from % priv->page_size);
254
 
255
        command = priv->command;
256
 
257
        DEBUG(MTD_DEBUG_LEVEL3, "READ: (%x) %x %x %x\n",
258
                command[0], command[1], command[2], command[3]);
259
 
260
        spi_message_init(&msg);
261
 
262
        x[0].tx_buf = command;
263
        x[0].len = 8;
264
        spi_message_add_tail(&x[0], &msg);
265
 
266
        x[1].rx_buf = buf;
267
        x[1].len = len;
268
        spi_message_add_tail(&x[1], &msg);
269
 
270
        mutex_lock(&priv->lock);
271
 
272
        /* Continuous read, max clock = f(car) which may be less than
273
         * the peak rate available.  Some chips support commands with
274
         * fewer "don't care" bytes.  Both buffers stay unchanged.
275
         */
276
        command[0] = OP_READ_CONTINUOUS;
277
        command[1] = (u8)(addr >> 16);
278
        command[2] = (u8)(addr >> 8);
279
        command[3] = (u8)(addr >> 0);
280
        /* plus 4 "don't care" bytes */
281
 
282
        status = spi_sync(priv->spi, &msg);
283
        mutex_unlock(&priv->lock);
284
 
285
        if (status >= 0) {
286
                *retlen = msg.actual_length - 8;
287
                status = 0;
288
        } else
289
                DEBUG(MTD_DEBUG_LEVEL1, "%s: read %x..%x --> %d\n",
290
                        priv->spi->dev.bus_id,
291
                        (unsigned)from, (unsigned)(from + len),
292
                        status);
293
        return status;
294
}
295
 
296
/*
297
 * Write to the DataFlash device.
298
 *   to     : Start offset in flash device
299
 *   len    : Amount to write
300
 *   retlen : Amount of data actually written
301
 *   buf    : Buffer containing the data
302
 */
303
static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
304
                                size_t * retlen, const u_char * buf)
305
{
306
        struct dataflash        *priv = (struct dataflash *)mtd->priv;
307
        struct spi_device       *spi = priv->spi;
308
        struct spi_transfer     x[2] = { { .tx_dma = 0, }, };
309
        struct spi_message      msg;
310
        unsigned int            pageaddr, addr, offset, writelen;
311
        size_t                  remaining = len;
312
        u_char                  *writebuf = (u_char *) buf;
313
        int                     status = -EINVAL;
314
        u8                      *command;
315
 
316
        DEBUG(MTD_DEBUG_LEVEL2, "%s: write 0x%x..0x%x\n",
317
                spi->dev.bus_id, (unsigned)to, (unsigned)(to + len));
318
 
319
        *retlen = 0;
320
 
321
        /* Sanity checks */
322
        if (!len)
323
                return 0;
324
        if ((to + len) > mtd->size)
325
                return -EINVAL;
326
 
327
        spi_message_init(&msg);
328
 
329
        x[0].tx_buf = command = priv->command;
330
        x[0].len = 4;
331
        spi_message_add_tail(&x[0], &msg);
332
 
333
        pageaddr = ((unsigned)to / priv->page_size);
334
        offset = ((unsigned)to % priv->page_size);
335
        if (offset + len > priv->page_size)
336
                writelen = priv->page_size - offset;
337
        else
338
                writelen = len;
339
 
340
        mutex_lock(&priv->lock);
341
        while (remaining > 0) {
342
                DEBUG(MTD_DEBUG_LEVEL3, "write @ %i:%i len=%i\n",
343
                        pageaddr, offset, writelen);
344
 
345
                /* REVISIT:
346
                 * (a) each page in a sector must be rewritten at least
347
                 *     once every 10K sibling erase/program operations.
348
                 * (b) for pages that are already erased, we could
349
                 *     use WRITE+MWRITE not PROGRAM for ~30% speedup.
350
                 * (c) WRITE to buffer could be done while waiting for
351
                 *     a previous MWRITE/MWERASE to complete ...
352
                 * (d) error handling here seems to be mostly missing.
353
                 *
354
                 * Two persistent bits per page, plus a per-sector counter,
355
                 * could support (a) and (b) ... we might consider using
356
                 * the second half of sector zero, which is just one block,
357
                 * to track that state.  (On AT91, that sector should also
358
                 * support boot-from-DataFlash.)
359
                 */
360
 
361
                addr = pageaddr << priv->page_offset;
362
 
363
                /* (1) Maybe transfer partial page to Buffer1 */
364
                if (writelen != priv->page_size) {
365
                        command[0] = OP_TRANSFER_BUF1;
366
                        command[1] = (addr & 0x00FF0000) >> 16;
367
                        command[2] = (addr & 0x0000FF00) >> 8;
368
                        command[3] = 0;
369
 
370
                        DEBUG(MTD_DEBUG_LEVEL3, "TRANSFER: (%x) %x %x %x\n",
371
                                command[0], command[1], command[2], command[3]);
372
 
373
                        status = spi_sync(spi, &msg);
374
                        if (status < 0)
375
                                DEBUG(MTD_DEBUG_LEVEL1, "%s: xfer %u -> %d \n",
376
                                        spi->dev.bus_id, addr, status);
377
 
378
                        (void) dataflash_waitready(priv->spi);
379
                }
380
 
381
                /* (2) Program full page via Buffer1 */
382
                addr += offset;
383
                command[0] = OP_PROGRAM_VIA_BUF1;
384
                command[1] = (addr & 0x00FF0000) >> 16;
385
                command[2] = (addr & 0x0000FF00) >> 8;
386
                command[3] = (addr & 0x000000FF);
387
 
388
                DEBUG(MTD_DEBUG_LEVEL3, "PROGRAM: (%x) %x %x %x\n",
389
                        command[0], command[1], command[2], command[3]);
390
 
391
                x[1].tx_buf = writebuf;
392
                x[1].len = writelen;
393
                spi_message_add_tail(x + 1, &msg);
394
                status = spi_sync(spi, &msg);
395
                spi_transfer_del(x + 1);
396
                if (status < 0)
397
                        DEBUG(MTD_DEBUG_LEVEL1, "%s: pgm %u/%u -> %d \n",
398
                                spi->dev.bus_id, addr, writelen, status);
399
 
400
                (void) dataflash_waitready(priv->spi);
401
 
402
 
403
#ifdef  CONFIG_DATAFLASH_WRITE_VERIFY
404
 
405
                /* (3) Compare to Buffer1 */
406
                addr = pageaddr << priv->page_offset;
407
                command[0] = OP_COMPARE_BUF1;
408
                command[1] = (addr & 0x00FF0000) >> 16;
409
                command[2] = (addr & 0x0000FF00) >> 8;
410
                command[3] = 0;
411
 
412
                DEBUG(MTD_DEBUG_LEVEL3, "COMPARE: (%x) %x %x %x\n",
413
                        command[0], command[1], command[2], command[3]);
414
 
415
                status = spi_sync(spi, &msg);
416
                if (status < 0)
417
                        DEBUG(MTD_DEBUG_LEVEL1, "%s: compare %u -> %d \n",
418
                                spi->dev.bus_id, addr, status);
419
 
420
                status = dataflash_waitready(priv->spi);
421
 
422
                /* Check result of the compare operation */
423
                if ((status & (1 << 6)) == 1) {
424
                        printk(KERN_ERR "%s: compare page %u, err %d\n",
425
                                spi->dev.bus_id, pageaddr, status);
426
                        remaining = 0;
427
                        status = -EIO;
428
                        break;
429
                } else
430
                        status = 0;
431
 
432
#endif  /* CONFIG_DATAFLASH_WRITE_VERIFY */
433
 
434
                remaining = remaining - writelen;
435
                pageaddr++;
436
                offset = 0;
437
                writebuf += writelen;
438
                *retlen += writelen;
439
 
440
                if (remaining > priv->page_size)
441
                        writelen = priv->page_size;
442
                else
443
                        writelen = remaining;
444
        }
445
        mutex_unlock(&priv->lock);
446
 
447
        return status;
448
}
449
 
450
/* ......................................................................... */
451
 
452
/*
453
 * Register DataFlash device with MTD subsystem.
454
 */
455
static int __devinit
456
add_dataflash(struct spi_device *spi, char *name,
457
                int nr_pages, int pagesize, int pageoffset)
458
{
459
        struct dataflash                *priv;
460
        struct mtd_info                 *device;
461
        struct flash_platform_data      *pdata = spi->dev.platform_data;
462
 
463
        priv = kzalloc(sizeof *priv, GFP_KERNEL);
464
        if (!priv)
465
                return -ENOMEM;
466
 
467
        mutex_init(&priv->lock);
468
        priv->spi = spi;
469
        priv->page_size = pagesize;
470
        priv->page_offset = pageoffset;
471
 
472
        /* name must be usable with cmdlinepart */
473
        sprintf(priv->name, "spi%d.%d-%s",
474
                        spi->master->bus_num, spi->chip_select,
475
                        name);
476
 
477
        device = &priv->mtd;
478
        device->name = (pdata && pdata->name) ? pdata->name : priv->name;
479
        device->size = nr_pages * pagesize;
480
        device->erasesize = pagesize;
481
        device->writesize = pagesize;
482
        device->owner = THIS_MODULE;
483
        device->type = MTD_DATAFLASH;
484
        device->flags = MTD_WRITEABLE;
485
        device->erase = dataflash_erase;
486
        device->read = dataflash_read;
487
        device->write = dataflash_write;
488
        device->priv = priv;
489
 
490
        dev_info(&spi->dev, "%s (%d KBytes)\n", name, device->size/1024);
491
        dev_set_drvdata(&spi->dev, priv);
492
 
493
        if (mtd_has_partitions()) {
494
                struct mtd_partition    *parts;
495
                int                     nr_parts = 0;
496
 
497
#ifdef CONFIG_MTD_CMDLINE_PARTS
498
                static const char *part_probes[] = { "cmdlinepart", NULL, };
499
 
500
                nr_parts = parse_mtd_partitions(device, part_probes, &parts, 0);
501
#endif
502
 
503
                if (nr_parts <= 0 && pdata && pdata->parts) {
504
                        parts = pdata->parts;
505
                        nr_parts = pdata->nr_parts;
506
                }
507
 
508
                if (nr_parts > 0) {
509
                        priv->partitioned = 1;
510
                        return add_mtd_partitions(device, parts, nr_parts);
511
                }
512
        } else if (pdata && pdata->nr_parts)
513
                dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
514
                                pdata->nr_parts, device->name);
515
 
516
        return add_mtd_device(device) == 1 ? -ENODEV : 0;
517
}
518
 
519
/*
520
 * Detect and initialize DataFlash device:
521
 *
522
 *   Device      Density         ID code          #Pages PageSize  Offset
523
 *   AT45DB011B  1Mbit   (128K)  xx0011xx (0x0c)    512    264      9
524
 *   AT45DB021B  2Mbit   (256K)  xx0101xx (0x14)   1025    264      9
525
 *   AT45DB041B  4Mbit   (512K)  xx0111xx (0x1c)   2048    264      9
526
 *   AT45DB081B  8Mbit   (1M)    xx1001xx (0x24)   4096    264      9
527
 *   AT45DB0161B 16Mbit  (2M)    xx1011xx (0x2c)   4096    528     10
528
 *   AT45DB0321B 32Mbit  (4M)    xx1101xx (0x34)   8192    528     10
529
 *   AT45DB0642  64Mbit  (8M)    xx111xxx (0x3c)   8192   1056     11
530
 *   AT45DB1282  128Mbit (16M)   xx0100xx (0x10)  16384   1056     11
531
 */
532
static int __devinit dataflash_probe(struct spi_device *spi)
533
{
534
        int status;
535
 
536
        status = dataflash_status(spi);
537
        if (status <= 0 || status == 0xff) {
538
                DEBUG(MTD_DEBUG_LEVEL1, "%s: status error %d\n",
539
                                spi->dev.bus_id, status);
540
                if (status == 0 || status == 0xff)
541
                        status = -ENODEV;
542
                return status;
543
        }
544
 
545
        /* if there's a device there, assume it's dataflash.
546
         * board setup should have set spi->max_speed_max to
547
         * match f(car) for continuous reads, mode 0 or 3.
548
         */
549
        switch (status & 0x3c) {
550
        case 0x0c:      /* 0 0 1 1 x x */
551
                status = add_dataflash(spi, "AT45DB011B", 512, 264, 9);
552
                break;
553
        case 0x14:      /* 0 1 0 1 x x */
554
                status = add_dataflash(spi, "AT45DB021B", 1025, 264, 9);
555
                break;
556
        case 0x1c:      /* 0 1 1 1 x x */
557
                status = add_dataflash(spi, "AT45DB041x", 2048, 264, 9);
558
                break;
559
        case 0x24:      /* 1 0 0 1 x x */
560
                status = add_dataflash(spi, "AT45DB081B", 4096, 264, 9);
561
                break;
562
        case 0x2c:      /* 1 0 1 1 x x */
563
                status = add_dataflash(spi, "AT45DB161x", 4096, 528, 10);
564
                break;
565
        case 0x34:      /* 1 1 0 1 x x */
566
                status = add_dataflash(spi, "AT45DB321x", 8192, 528, 10);
567
                break;
568
        case 0x38:      /* 1 1 1 x x x */
569
        case 0x3c:
570
                status = add_dataflash(spi, "AT45DB642x", 8192, 1056, 11);
571
                break;
572
        /* obsolete AT45DB1282 not (yet?) supported */
573
        default:
574
                DEBUG(MTD_DEBUG_LEVEL1, "%s: unsupported device (%x)\n",
575
                                spi->dev.bus_id, status & 0x3c);
576
                status = -ENODEV;
577
        }
578
 
579
        if (status < 0)
580
                DEBUG(MTD_DEBUG_LEVEL1, "%s: add_dataflash --> %d\n",
581
                                spi->dev.bus_id, status);
582
 
583
        return status;
584
}
585
 
586
static int __devexit dataflash_remove(struct spi_device *spi)
587
{
588
        struct dataflash        *flash = dev_get_drvdata(&spi->dev);
589
        int                     status;
590
 
591
        DEBUG(MTD_DEBUG_LEVEL1, "%s: remove\n", spi->dev.bus_id);
592
 
593
        if (mtd_has_partitions() && flash->partitioned)
594
                status = del_mtd_partitions(&flash->mtd);
595
        else
596
                status = del_mtd_device(&flash->mtd);
597
        if (status == 0)
598
                kfree(flash);
599
        return status;
600
}
601
 
602
static struct spi_driver dataflash_driver = {
603
        .driver = {
604
                .name           = "mtd_dataflash",
605
                .bus            = &spi_bus_type,
606
                .owner          = THIS_MODULE,
607
        },
608
 
609
        .probe          = dataflash_probe,
610
        .remove         = __devexit_p(dataflash_remove),
611
 
612
        /* FIXME:  investigate suspend and resume... */
613
};
614
 
615
static int __init dataflash_init(void)
616
{
617
        return spi_register_driver(&dataflash_driver);
618
}
619
module_init(dataflash_init);
620
 
621
static void __exit dataflash_exit(void)
622
{
623
        spi_unregister_driver(&dataflash_driver);
624
}
625
module_exit(dataflash_exit);
626
 
627
 
628
MODULE_LICENSE("GPL");
629
MODULE_AUTHOR("Andrew Victor, David Brownell");
630
MODULE_DESCRIPTION("MTD DataFlash driver");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.