return extp;
}
+/* This routine is made available to other mtd code via
+ * inter_module_register. It must only be accessed through
+ * inter_module_get which will bump the use count of this module. The
+ * addresses passed back in cfi are valid as long as the use count of
+ * this module is non-zero, i.e. between inter_module_get and
+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000.
+ */
struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
{
struct cfi_private *cfi = map->fldrv_priv;
mtd->resume = cfi_intelext_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
- mtd->writesize = 1;
mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
for (i=0; i< cfi->numchips; i++) {
cfi->chips[i].word_write_time = 1<<cfi->cfiq->WordWriteTimeoutTyp;
cfi->chips[i].buffer_write_time = 1<<cfi->cfiq->BufWriteTimeoutTyp;
- cfi->chips[i].erase_time = 1000<<cfi->cfiq->BlockEraseTimeoutTyp;
+ cfi->chips[i].erase_time = 1<<cfi->cfiq->BlockEraseTimeoutTyp;
cfi->chips[i].ref_point_counter = 0;
init_waitqueue_head(&(cfi->chips[i].wq));
}
return cfi_intelext_setup(mtd);
}
-struct mtd_info *cfi_cmdset_0003(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001")));
-struct mtd_info *cfi_cmdset_0200(struct map_info *map, int primary) __attribute__((alias("cfi_cmdset_0001")));
-EXPORT_SYMBOL_GPL(cfi_cmdset_0001);
-EXPORT_SYMBOL_GPL(cfi_cmdset_0003);
-EXPORT_SYMBOL_GPL(cfi_cmdset_0200);
static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
{
if (extp->MinorVersion >= '4') {
struct cfi_intelext_programming_regioninfo *prinfo;
prinfo = (struct cfi_intelext_programming_regioninfo *)&extp->extra[offs];
- mtd->writesize = cfi->interleave << prinfo->ProgRegShift;
+ MTD_PROGREGION_SIZE(mtd) = cfi->interleave << prinfo->ProgRegShift;
MTD_PROGREGION_CTRLMODE_VALID(mtd) = cfi->interleave * prinfo->ControlValid;
MTD_PROGREGION_CTRLMODE_INVALID(mtd) = cfi->interleave * prinfo->ControlInvalid;
- mtd->flags &= ~MTD_BIT_WRITEABLE;
+ mtd->flags |= MTD_PROGRAM_REGIONS;
printk(KERN_DEBUG "%s: program region size/ctrl_valid/ctrl_inval = %d/%d/%d\n",
- map->name, mtd->writesize,
+ map->name, MTD_PROGREGION_SIZE(mtd),
MTD_PROGREGION_CTRLMODE_VALID(mtd),
MTD_PROGREGION_CTRLMODE_INVALID(mtd));
}
/*
* When a delay is required for the flash operation to complete, the
- * xip_wait_for_operation() function is polling for both the given timeout
- * and pending (but still masked) hardware interrupts. Whenever there is an
- * interrupt pending then the flash erase or write operation is suspended,
- * array mode restored and interrupts unmasked. Task scheduling might also
- * happen at that point. The CPU eventually returns from the interrupt or
- * the call to schedule() and the suspended flash operation is resumed for
- * the remaining of the delay period.
+ * xip_udelay() function is polling for both the given timeout and pending
+ * (but still masked) hardware interrupts. Whenever there is an interrupt
+ * pending then the flash erase or write operation is suspended, array mode
+ * restored and interrupts unmasked. Task scheduling might also happen at that
+ * point. The CPU eventually returns from the interrupt or the call to
+ * schedule() and the suspended flash operation is resumed for the remaining
+ * of the delay period.
*
* Warning: this function _will_ fool interrupt latency tracing tools.
*/
-static int __xipram xip_wait_for_operation(
- struct map_info *map, struct flchip *chip,
- unsigned long adr, unsigned int chip_op_time )
+static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int usec)
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *cfip = cfi->cmdset_priv;
map_word status, OK = CMD(0x80);
- unsigned long usec, suspended, start, done;
+ unsigned long suspended, start = xip_currtime();
flstate_t oldstate, newstate;
- start = xip_currtime();
- usec = chip_op_time * 8;
- if (usec == 0)
- usec = 500000;
- done = 0;
-
do {
cpu_relax();
if (xip_irqpending() && cfip &&
* we resume the whole thing at once). Yes, it
* can happen!
*/
- usec -= done;
map_write(map, CMD(0xb0), adr);
map_write(map, CMD(0x70), adr);
+ usec -= xip_elapsed_since(start);
suspended = xip_currtime();
do {
if (xip_elapsed_since(suspended) > 100000) {
* This is a critical error but there
* is not much we can do here.
*/
- return -EIO;
+ return;
}
status = map_read(map, adr);
} while (!map_word_andequal(map, status, OK, OK));
xip_cpu_idle();
}
status = map_read(map, adr);
- done = xip_elapsed_since(start);
} while (!map_word_andequal(map, status, OK, OK)
- && done < usec);
-
- return (done >= usec) ? -ETIME : 0;
+ && xip_elapsed_since(start) < usec);
}
+#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec)
+
/*
* The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
* the flash is actively programming or erasing since we have to poll for
* the operation to complete anyway. We can't do that in a generic way with
* a XIP setup so do it before the actual flash operation in this case
- * and stub it out from INVAL_CACHE_AND_WAIT.
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
*/
#define XIP_INVAL_CACHED_RANGE(map, from, size) \
INVALIDATE_CACHED_RANGE(map, from, size)
-#define INVAL_CACHE_AND_WAIT(map, chip, cmd_adr, inval_adr, inval_len, usec) \
- xip_wait_for_operation(map, chip, cmd_adr, usec)
+#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \
+ UDELAY(map, chip, cmd_adr, usec)
+
+/*
+ * Extra notes:
+ *
+ * Activating this XIP support changes the way the code works a bit. For
+ * example the code to suspend the current process when concurrent access
+ * happens is never executed because xip_udelay() will always return with the
+ * same chip state as it was entered with. This is why there is no care for
+ * the presence of add_wait_queue() or schedule() calls from within a couple
+ * xip_disable()'d areas of code, like in do_erase_oneblock for example.
+ * The queueing and scheduling are always happening within xip_udelay().
+ *
+ * Similarly, get_chip() and put_chip() just happen to always be executed
+ * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
+ * is in array mode, therefore never executing many cases therein and not
+ * causing any problem with XIP.
+ */
#else
#define xip_disable(map, chip, adr)
#define xip_enable(map, chip, adr)
#define XIP_INVAL_CACHED_RANGE(x...)
-#define INVAL_CACHE_AND_WAIT inval_cache_and_wait_for_operation
-
-static int inval_cache_and_wait_for_operation(
- struct map_info *map, struct flchip *chip,
- unsigned long cmd_adr, unsigned long inval_adr, int inval_len,
- unsigned int chip_op_time)
-{
- struct cfi_private *cfi = map->fldrv_priv;
- map_word status, status_OK = CMD(0x80);
- int chip_state = chip->state;
- unsigned int timeo, sleep_time;
-
- spin_unlock(chip->mutex);
- if (inval_len)
- INVALIDATE_CACHED_RANGE(map, inval_adr, inval_len);
- spin_lock(chip->mutex);
-
- /* set our timeout to 8 times the expected delay */
- timeo = chip_op_time * 8;
- if (!timeo)
- timeo = 500000;
- sleep_time = chip_op_time / 2;
-
- for (;;) {
- status = map_read(map, cmd_adr);
- if (map_word_andequal(map, status, status_OK, status_OK))
- break;
-
- if (!timeo) {
- map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
- return -ETIME;
- }
- /* OK Still waiting. Drop the lock, wait a while and retry. */
- spin_unlock(chip->mutex);
- if (sleep_time >= 1000000/HZ) {
- /*
- * Half of the normal delay still remaining
- * can be performed with a sleeping delay instead
- * of busy waiting.
- */
- msleep(sleep_time/1000);
- timeo -= sleep_time;
- sleep_time = 1000000/HZ;
- } else {
- udelay(1);
- cond_resched();
- timeo--;
- }
- spin_lock(chip->mutex);
-
- if (chip->state != chip_state) {
- /* Someone's suspended the operation: sleep */
- DECLARE_WAITQUEUE(wait, current);
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&chip->wq, &wait);
- spin_unlock(chip->mutex);
- schedule();
- remove_wait_queue(&chip->wq, &wait);
- spin_lock(chip->mutex);
- }
- }
-
- /* Done and happy. */
- chip->state = FL_STATUS;
- return 0;
-}
+#define UDELAY(map, chip, adr, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr, adr, len, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ INVALIDATE_CACHED_RANGE(map, adr, len); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
#endif
-#define WAIT_TIMEOUT(map, chip, adr, udelay) \
- INVAL_CACHE_AND_WAIT(map, chip, adr, 0, 0, udelay);
-
-
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
{
unsigned long cmd_addr;
unsigned long adr, map_word datum, int mode)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status, write_cmd;
- int ret=0;
+ map_word status, status_OK, write_cmd;
+ unsigned long timeo;
+ int z, ret=0;
adr += chip->start;
+ /* Let's determine those according to the interleave only once */
+ status_OK = CMD(0x80);
switch (mode) {
case FL_WRITING:
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0x40) : CMD(0x41);
map_write(map, datum, adr);
chip->state = mode;
- ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
- adr, map_bankwidth(map),
- chip->word_write_time);
- if (ret) {
- xip_enable(map, chip, adr);
- printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
- goto out;
+ INVALIDATE_CACHE_UDELAY(map, chip, adr,
+ adr, map_bankwidth(map),
+ chip->word_write_time);
+
+ timeo = jiffies + (HZ/2);
+ z = 0;
+ for (;;) {
+ if (chip->state != mode) {
+ /* Someone's suspended the write. Sleep */
+ DECLARE_WAITQUEUE(wait, current);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ timeo = jiffies + (HZ / 2); /* FIXME */
+ spin_lock(chip->mutex);
+ continue;
+ }
+
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
+ break;
+
+ /* OK Still waiting */
+ if (time_after(jiffies, timeo)) {
+ map_write(map, CMD(0x70), adr);
+ chip->state = FL_STATUS;
+ xip_enable(map, chip, adr);
+ printk(KERN_ERR "%s: word write error (status timeout)\n", map->name);
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ z++;
+ UDELAY(map, chip, adr, 1);
+ }
+ if (!z) {
+ chip->word_write_time--;
+ if (!chip->word_write_time)
+ chip->word_write_time = 1;
}
+ if (z > 1)
+ chip->word_write_time++;
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
/* check for errors */
- status = map_read(map, adr);
if (map_word_bitsset(map, status, CMD(0x1a))) {
unsigned long chipstatus = MERGESTATUS(status);
unsigned long *pvec_seek, int len)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status, write_cmd, datum;
- unsigned long cmd_adr;
- int ret, wbufsize, word_gap, words;
+ map_word status, status_OK, write_cmd, datum;
+ unsigned long cmd_adr, timeo;
+ int wbufsize, z, ret=0, word_gap, words;
const struct kvec *vec;
unsigned long vec_seek;
cmd_adr = adr & ~(wbufsize-1);
/* Let's determine this according to the interleave only once */
+ status_OK = CMD(0x80);
write_cmd = (cfi->cfiq->P_ID != 0x0200) ? CMD(0xe8) : CMD(0xe9);
spin_lock(chip->mutex);
ENABLE_VPP(map);
xip_disable(map, chip, cmd_adr);
- /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
+ /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set
[...], the device will not accept any more Write to Buffer commands".
So we must check here and reset those bits if they're set. Otherwise
we're just pissing in the wind */
- if (chip->state != FL_STATUS) {
+ if (chip->state != FL_STATUS)
map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
- }
status = map_read(map, cmd_adr);
if (map_word_bitsset(map, status, CMD(0x30))) {
xip_enable(map, chip, cmd_adr);
}
chip->state = FL_WRITING_TO_BUFFER;
- map_write(map, write_cmd, cmd_adr);
- ret = WAIT_TIMEOUT(map, chip, cmd_adr, 0);
- if (ret) {
- /* Argh. Not ready for write to buffer */
- map_word Xstatus = map_read(map, cmd_adr);
- map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
+
+ z = 0;
+ for (;;) {
+ map_write(map, write_cmd, cmd_adr);
+
status = map_read(map, cmd_adr);
- map_write(map, CMD(0x50), cmd_adr);
- map_write(map, CMD(0x70), cmd_adr);
- xip_enable(map, chip, cmd_adr);
- printk(KERN_ERR "%s: Chip not ready for buffer write. Xstatus = %lx, status = %lx\n",
- map->name, Xstatus.x[0], status.x[0]);
- goto out;
+ if (map_word_andequal(map, status, status_OK, status_OK))
+ break;
+
+ UDELAY(map, chip, cmd_adr, 1);
+
+ if (++z > 20) {
+ /* Argh. Not ready for write to buffer */
+ map_word Xstatus;
+ map_write(map, CMD(0x70), cmd_adr);
+ chip->state = FL_STATUS;
+ Xstatus = map_read(map, cmd_adr);
+ /* Odd. Clear status bits */
+ map_write(map, CMD(0x50), cmd_adr);
+ map_write(map, CMD(0x70), cmd_adr);
+ xip_enable(map, chip, cmd_adr);
+ printk(KERN_ERR "%s: Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
+ map->name, status.x[0], Xstatus.x[0]);
+ ret = -EIO;
+ goto out;
+ }
}
/* Figure out the number of words to write */
map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
- ret = INVAL_CACHE_AND_WAIT(map, chip, cmd_adr,
- adr, len,
- chip->buffer_write_time);
- if (ret) {
- map_write(map, CMD(0x70), cmd_adr);
- chip->state = FL_STATUS;
- xip_enable(map, chip, cmd_adr);
- printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
- goto out;
+ INVALIDATE_CACHE_UDELAY(map, chip, cmd_adr,
+ adr, len,
+ chip->buffer_write_time);
+
+ timeo = jiffies + (HZ/2);
+ z = 0;
+ for (;;) {
+ if (chip->state != FL_WRITING) {
+ /* Someone's suspended the write. Sleep */
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ timeo = jiffies + (HZ / 2); /* FIXME */
+ spin_lock(chip->mutex);
+ continue;
+ }
+
+ status = map_read(map, cmd_adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
+ break;
+
+ /* OK Still waiting */
+ if (time_after(jiffies, timeo)) {
+ map_write(map, CMD(0x70), cmd_adr);
+ chip->state = FL_STATUS;
+ xip_enable(map, chip, cmd_adr);
+ printk(KERN_ERR "%s: buffer write error (status timeout)\n", map->name);
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ z++;
+ UDELAY(map, chip, cmd_adr, 1);
}
+ if (!z) {
+ chip->buffer_write_time--;
+ if (!chip->buffer_write_time)
+ chip->buffer_write_time = 1;
+ }
+ if (z > 1)
+ chip->buffer_write_time++;
+
+ /* Done and happy. */
+ chip->state = FL_STATUS;
/* check for errors */
- status = map_read(map, cmd_adr);
if (map_word_bitsset(map, status, CMD(0x1a))) {
unsigned long chipstatus = MERGESTATUS(status);
if (chipnum == cfi->numchips)
return 0;
}
-
- /* Be nice and reschedule with the chip in a usable state for other
- processes. */
- cond_resched();
-
} while (len);
return 0;
unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status;
+ map_word status, status_OK;
+ unsigned long timeo;
int retries = 3;
- int ret;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret = 0;
adr += chip->start;
+ /* Let's determine this according to the interleave only once */
+ status_OK = CMD(0x80);
+
retry:
spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_ERASING);
chip->state = FL_ERASING;
chip->erase_suspended = 0;
- ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
- adr, len,
- chip->erase_time);
- if (ret) {
- map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
- xip_enable(map, chip, adr);
- printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
- goto out;
+ INVALIDATE_CACHE_UDELAY(map, chip, adr,
+ adr, len,
+ chip->erase_time*1000/2);
+
+ /* FIXME. Use a timer to check this, and return immediately. */
+ /* Once the state machine's known to be working I'll do that */
+
+ timeo = jiffies + (HZ*20);
+ for (;;) {
+ if (chip->state != FL_ERASING) {
+ /* Someone's suspended the erase. Sleep */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ spin_lock(chip->mutex);
+ continue;
+ }
+ if (chip->erase_suspended) {
+ /* This erase was suspended and resumed.
+ Adjust the timeout */
+ timeo = jiffies + (HZ*20); /* FIXME */
+ chip->erase_suspended = 0;
+ }
+
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
+ break;
+
+ /* OK Still waiting */
+ if (time_after(jiffies, timeo)) {
+ map_write(map, CMD(0x70), adr);
+ chip->state = FL_STATUS;
+ xip_enable(map, chip, adr);
+ printk(KERN_ERR "%s: block erase error: (status timeout)\n", map->name);
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ UDELAY(map, chip, adr, 1000000/HZ);
}
/* We've broken this before. It doesn't hurt to be safe */
ret = -EIO;
} else if (chipstatus & 0x20 && retries--) {
printk(KERN_DEBUG "block erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
+ timeo = jiffies + HZ;
put_chip(map, chip, adr);
spin_unlock(chip->mutex);
goto retry;
{
struct cfi_private *cfi = map->fldrv_priv;
struct cfi_pri_intelext *extp = cfi->cmdset_priv;
- int udelay;
+ map_word status, status_OK;
+ unsigned long timeo = jiffies + HZ;
int ret;
adr += chip->start;
+ /* Let's determine this according to the interleave only once */
+ status_OK = CMD(0x80);
+
spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_LOCKING);
if (ret) {
* If Instant Individual Block Locking supported then no need
* to delay.
*/
- udelay = (!extp || !(extp->FeatureSupport & (1 << 5))) ? 1000000/HZ : 0;
- ret = WAIT_TIMEOUT(map, chip, adr, udelay);
- if (ret) {
- map_write(map, CMD(0x70), adr);
- chip->state = FL_STATUS;
- xip_enable(map, chip, adr);
- printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
- goto out;
+ if (!extp || !(extp->FeatureSupport & (1 << 5)))
+ UDELAY(map, chip, adr, 1000000/HZ);
+
+ /* FIXME. Use a timer to check this, and return immediately. */
+ /* Once the state machine's known to be working I'll do that */
+
+ timeo = jiffies + (HZ*20);
+ for (;;) {
+
+ status = map_read(map, adr);
+ if (map_word_andequal(map, status, status_OK, status_OK))
+ break;
+
+ /* OK Still waiting */
+ if (time_after(jiffies, timeo)) {
+ map_write(map, CMD(0x70), adr);
+ chip->state = FL_STATUS;
+ xip_enable(map, chip, adr);
+ printk(KERN_ERR "%s: block unlock error: (status timeout)\n", map->name);
+ put_chip(map, chip, adr);
+ spin_unlock(chip->mutex);
+ return -EIO;
+ }
+
+ /* Latency issues. Drop the lock, wait a while and retry */
+ UDELAY(map, chip, adr, 1);
}
+ /* Done and happy. */
+ chip->state = FL_STATUS;
xip_enable(map, chip, adr);
-out: put_chip(map, chip, adr);
+ put_chip(map, chip, adr);
spin_unlock(chip->mutex);
- return ret;
+ return 0;
}
static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
kfree(mtd->eraseregions);
}
+static char im_name_0001[] = "cfi_cmdset_0001";
+static char im_name_0003[] = "cfi_cmdset_0003";
+static char im_name_0200[] = "cfi_cmdset_0200";
+
+static int __init cfi_intelext_init(void)
+{
+ inter_module_register(im_name_0001, THIS_MODULE, &cfi_cmdset_0001);
+ inter_module_register(im_name_0003, THIS_MODULE, &cfi_cmdset_0001);
+ inter_module_register(im_name_0200, THIS_MODULE, &cfi_cmdset_0001);
+ return 0;
+}
+
+static void __exit cfi_intelext_exit(void)
+{
+ inter_module_unregister(im_name_0001);
+ inter_module_unregister(im_name_0003);
+ inter_module_unregister(im_name_0200);
+}
+
+module_init(cfi_intelext_init);
+module_exit(cfi_intelext_exit);
+
MODULE_LICENSE("GPL");
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org> et al.");
MODULE_DESCRIPTION("MTD chip driver for Intel/Sharp flash chips");
-MODULE_ALIAS("cfi_cmdset_0003");
-MODULE_ALIAS("cfi_cmdset_0200");