physmap-core.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Normal mappings of chips in physical memory
  4. *
  5. * Copyright (C) 2003 MontaVista Software Inc.
  6. * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
  7. *
  8. * 031022 - [jsun] add run-time configure and partition setup
  9. *
  10. * Device tree support:
  11. * Copyright (C) 2006 MontaVista Software Inc.
  12. * Author: Vitaly Wool <vwool@ru.mvista.com>
  13. *
  14. * Revised to handle newer style flash binding by:
  15. * Copyright (C) 2007 David Gibson, IBM Corporation.
  16. *
  17. * GPIO address extension:
  18. * Handle the case where a flash device is mostly addressed using physical
  19. * line and supplemented by GPIOs. This way you can hook up say a 8MiB flash
  20. * to a 2MiB memory range and use the GPIOs to select a particular range.
  21. *
  22. * Copyright © 2000 Nicolas Pitre <nico@cam.org>
  23. * Copyright © 2005-2009 Analog Devices Inc.
  24. */
  25. #include <linux/module.h>
  26. #include <linux/types.h>
  27. #include <linux/kernel.h>
  28. #include <linux/init.h>
  29. #include <linux/slab.h>
  30. #include <linux/device.h>
  31. #include <linux/platform_device.h>
  32. #include <linux/property.h>
  33. #include <linux/mtd/mtd.h>
  34. #include <linux/mtd/map.h>
  35. #include <linux/mtd/partitions.h>
  36. #include <linux/mtd/physmap.h>
  37. #include <linux/mtd/concat.h>
  38. #include <linux/mtd/cfi_endian.h>
  39. #include <linux/io.h>
  40. #include <linux/of.h>
  41. #include <linux/pm_runtime.h>
  42. #include <linux/gpio/consumer.h>
  43. #include "physmap-bt1-rom.h"
  44. #include "physmap-gemini.h"
  45. #include "physmap-ixp4xx.h"
  46. #include "physmap-versatile.h"
  47. struct physmap_flash_info {
  48. unsigned int nmaps;
  49. struct mtd_info **mtds;
  50. struct mtd_info *cmtd;
  51. struct map_info *maps;
  52. spinlock_t vpp_lock;
  53. int vpp_refcnt;
  54. const char *probe_type;
  55. const char * const *part_types;
  56. unsigned int nparts;
  57. const struct mtd_partition *parts;
  58. struct gpio_descs *gpios;
  59. unsigned int gpio_values;
  60. unsigned int win_order;
  61. };
  62. static void physmap_flash_remove(struct platform_device *dev)
  63. {
  64. struct physmap_flash_info *info;
  65. struct physmap_flash_data *physmap_data;
  66. int i;
  67. info = platform_get_drvdata(dev);
  68. if (info->cmtd) {
  69. WARN_ON(mtd_device_unregister(info->cmtd));
  70. if (info->cmtd != info->mtds[0])
  71. mtd_concat_destroy(info->cmtd);
  72. }
  73. for (i = 0; i < info->nmaps; i++) {
  74. if (info->mtds[i])
  75. map_destroy(info->mtds[i]);
  76. }
  77. physmap_data = dev_get_platdata(&dev->dev);
  78. if (physmap_data && physmap_data->exit)
  79. physmap_data->exit(dev);
  80. pm_runtime_put(&dev->dev);
  81. pm_runtime_disable(&dev->dev);
  82. }
  83. static void physmap_set_vpp(struct map_info *map, int state)
  84. {
  85. struct platform_device *pdev;
  86. struct physmap_flash_data *physmap_data;
  87. struct physmap_flash_info *info;
  88. unsigned long flags;
  89. pdev = (struct platform_device *)map->map_priv_1;
  90. physmap_data = dev_get_platdata(&pdev->dev);
  91. if (!physmap_data->set_vpp)
  92. return;
  93. info = platform_get_drvdata(pdev);
  94. spin_lock_irqsave(&info->vpp_lock, flags);
  95. if (state) {
  96. if (++info->vpp_refcnt == 1) /* first nested 'on' */
  97. physmap_data->set_vpp(pdev, 1);
  98. } else {
  99. if (--info->vpp_refcnt == 0) /* last nested 'off' */
  100. physmap_data->set_vpp(pdev, 0);
  101. }
  102. spin_unlock_irqrestore(&info->vpp_lock, flags);
  103. }
  104. #if IS_ENABLED(CONFIG_MTD_PHYSMAP_GPIO_ADDR)
  105. static void physmap_set_addr_gpios(struct physmap_flash_info *info,
  106. unsigned long ofs)
  107. {
  108. unsigned int i;
  109. ofs >>= info->win_order;
  110. if (info->gpio_values == ofs)
  111. return;
  112. for (i = 0; i < info->gpios->ndescs; i++) {
  113. if ((BIT(i) & ofs) == (BIT(i) & info->gpio_values))
  114. continue;
  115. gpiod_set_value(info->gpios->desc[i], !!(BIT(i) & ofs));
  116. }
  117. info->gpio_values = ofs;
  118. }
  119. #define win_mask(order) (BIT(order) - 1)
  120. static map_word physmap_addr_gpios_read(struct map_info *map,
  121. unsigned long ofs)
  122. {
  123. struct platform_device *pdev;
  124. struct physmap_flash_info *info;
  125. map_word mw;
  126. u16 word;
  127. pdev = (struct platform_device *)map->map_priv_1;
  128. info = platform_get_drvdata(pdev);
  129. physmap_set_addr_gpios(info, ofs);
  130. word = readw(map->virt + (ofs & win_mask(info->win_order)));
  131. mw.x[0] = word;
  132. return mw;
  133. }
  134. static void physmap_addr_gpios_copy_from(struct map_info *map, void *buf,
  135. unsigned long ofs, ssize_t len)
  136. {
  137. struct platform_device *pdev;
  138. struct physmap_flash_info *info;
  139. pdev = (struct platform_device *)map->map_priv_1;
  140. info = platform_get_drvdata(pdev);
  141. while (len) {
  142. unsigned int winofs = ofs & win_mask(info->win_order);
  143. unsigned int chunklen = min_t(unsigned int, len,
  144. BIT(info->win_order) - winofs);
  145. physmap_set_addr_gpios(info, ofs);
  146. memcpy_fromio(buf, map->virt + winofs, chunklen);
  147. len -= chunklen;
  148. buf += chunklen;
  149. ofs += chunklen;
  150. }
  151. }
  152. static void physmap_addr_gpios_write(struct map_info *map, map_word mw,
  153. unsigned long ofs)
  154. {
  155. struct platform_device *pdev;
  156. struct physmap_flash_info *info;
  157. u16 word;
  158. pdev = (struct platform_device *)map->map_priv_1;
  159. info = platform_get_drvdata(pdev);
  160. physmap_set_addr_gpios(info, ofs);
  161. word = mw.x[0];
  162. writew(word, map->virt + (ofs & win_mask(info->win_order)));
  163. }
  164. static void physmap_addr_gpios_copy_to(struct map_info *map, unsigned long ofs,
  165. const void *buf, ssize_t len)
  166. {
  167. struct platform_device *pdev;
  168. struct physmap_flash_info *info;
  169. pdev = (struct platform_device *)map->map_priv_1;
  170. info = platform_get_drvdata(pdev);
  171. while (len) {
  172. unsigned int winofs = ofs & win_mask(info->win_order);
  173. unsigned int chunklen = min_t(unsigned int, len,
  174. BIT(info->win_order) - winofs);
  175. physmap_set_addr_gpios(info, ofs);
  176. memcpy_toio(map->virt + winofs, buf, chunklen);
  177. len -= chunklen;
  178. buf += chunklen;
  179. ofs += chunklen;
  180. }
  181. }
  182. static int physmap_addr_gpios_map_init(struct map_info *map)
  183. {
  184. map->phys = NO_XIP;
  185. map->read = physmap_addr_gpios_read;
  186. map->copy_from = physmap_addr_gpios_copy_from;
  187. map->write = physmap_addr_gpios_write;
  188. map->copy_to = physmap_addr_gpios_copy_to;
  189. return 0;
  190. }
  191. #else
  192. static int physmap_addr_gpios_map_init(struct map_info *map)
  193. {
  194. return -ENOTSUPP;
  195. }
  196. #endif
  197. #if IS_ENABLED(CONFIG_MTD_PHYSMAP_OF)
  198. static const struct of_device_id of_flash_match[] = {
  199. {
  200. .compatible = "cfi-flash",
  201. .data = "cfi_probe",
  202. },
  203. {
  204. /*
  205. * FIXME: JEDEC chips can't be safely and reliably
  206. * probed, although the mtd code gets it right in
  207. * practice most of the time. We should use the
  208. * vendor and device ids specified by the binding to
  209. * bypass the heuristic probe code, but the mtd layer
  210. * provides, at present, no interface for doing so
  211. * :(.
  212. */
  213. .compatible = "jedec-flash",
  214. .data = "jedec_probe",
  215. },
  216. {
  217. .compatible = "mtd-ram",
  218. .data = "map_ram",
  219. },
  220. {
  221. .compatible = "mtd-rom",
  222. .data = "map_rom",
  223. },
  224. {
  225. .type = "rom",
  226. .compatible = "direct-mapped"
  227. },
  228. { /* sentinel */ },
  229. };
  230. MODULE_DEVICE_TABLE(of, of_flash_match);
  231. static const char * const of_default_part_probes[] = {
  232. "cmdlinepart", "ofpart", "ofoldpart", "RedBoot", NULL
  233. };
  234. static const char * const *of_get_part_probes(struct platform_device *dev)
  235. {
  236. struct device_node *dp = dev->dev.of_node;
  237. const char **res;
  238. int count;
  239. count = of_property_count_strings(dp, "linux,part-probe");
  240. if (count < 0)
  241. return of_default_part_probes;
  242. res = devm_kcalloc(&dev->dev, count + 1, sizeof(*res), GFP_KERNEL);
  243. if (!res)
  244. return NULL;
  245. count = of_property_read_string_array(dp, "linux,part-probe", res,
  246. count);
  247. if (count < 0)
  248. return NULL;
  249. return res;
  250. }
  251. static const char *of_select_probe_type(struct platform_device *dev)
  252. {
  253. struct device_node *dp = dev->dev.of_node;
  254. const char *probe_type;
  255. probe_type = device_get_match_data(&dev->dev);
  256. if (probe_type)
  257. return probe_type;
  258. dev_warn(&dev->dev,
  259. "Device tree uses obsolete \"direct-mapped\" flash binding\n");
  260. of_property_read_string(dp, "probe-type", &probe_type);
  261. if (!probe_type)
  262. return NULL;
  263. if (!strcmp(probe_type, "CFI")) {
  264. probe_type = "cfi_probe";
  265. } else if (!strcmp(probe_type, "JEDEC")) {
  266. probe_type = "jedec_probe";
  267. } else if (!strcmp(probe_type, "ROM")) {
  268. probe_type = "map_rom";
  269. } else {
  270. dev_warn(&dev->dev,
  271. "obsolete_probe: don't know probe type '%s', mapping as rom\n",
  272. probe_type);
  273. probe_type = "map_rom";
  274. }
  275. return probe_type;
  276. }
  277. static int physmap_flash_of_init(struct platform_device *dev)
  278. {
  279. struct physmap_flash_info *info = platform_get_drvdata(dev);
  280. struct device_node *dp = dev->dev.of_node;
  281. const char *mtd_name = NULL;
  282. int err, swap = 0;
  283. bool map_indirect;
  284. unsigned int i;
  285. u32 bankwidth;
  286. if (!dp)
  287. return -EINVAL;
  288. info->probe_type = of_select_probe_type(dev);
  289. info->part_types = of_get_part_probes(dev);
  290. if (!info->part_types)
  291. return -ENOMEM;
  292. of_property_read_string(dp, "linux,mtd-name", &mtd_name);
  293. map_indirect = of_property_read_bool(dp, "no-unaligned-direct-access");
  294. err = of_property_read_u32(dp, "bank-width", &bankwidth);
  295. if (err) {
  296. dev_err(&dev->dev, "Can't get bank width from device tree\n");
  297. return err;
  298. }
  299. if (of_property_read_bool(dp, "big-endian"))
  300. swap = CFI_BIG_ENDIAN;
  301. else if (of_property_read_bool(dp, "little-endian"))
  302. swap = CFI_LITTLE_ENDIAN;
  303. for (i = 0; i < info->nmaps; i++) {
  304. info->maps[i].name = mtd_name;
  305. info->maps[i].swap = swap;
  306. info->maps[i].bankwidth = bankwidth;
  307. info->maps[i].device_node = dp;
  308. err = of_flash_probe_bt1_rom(dev, dp, &info->maps[i]);
  309. if (err)
  310. return err;
  311. err = of_flash_probe_gemini(dev, dp, &info->maps[i]);
  312. if (err)
  313. return err;
  314. err = of_flash_probe_ixp4xx(dev, dp, &info->maps[i]);
  315. if (err)
  316. return err;
  317. err = of_flash_probe_versatile(dev, dp, &info->maps[i]);
  318. if (err)
  319. return err;
  320. /*
  321. * On some platforms (e.g. MPC5200) a direct 1:1 mapping
  322. * may cause problems with JFFS2 usage, as the local bus (LPB)
  323. * doesn't support unaligned accesses as implemented in the
  324. * JFFS2 code via memcpy(). By setting NO_XIP, the
  325. * flash will not be exposed directly to the MTD users
  326. * (e.g. JFFS2) any more.
  327. */
  328. if (map_indirect)
  329. info->maps[i].phys = NO_XIP;
  330. }
  331. return 0;
  332. }
  333. #else /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
  334. #define of_flash_match NULL
  335. static int physmap_flash_of_init(struct platform_device *dev)
  336. {
  337. return -ENOTSUPP;
  338. }
  339. #endif /* IS_ENABLED(CONFIG_MTD_PHYSMAP_OF) */
  340. static const char * const rom_probe_types[] = {
  341. "cfi_probe", "jedec_probe", "qinfo_probe", "map_rom",
  342. };
  343. static const char * const part_probe_types[] = {
  344. "cmdlinepart", "RedBoot", "afs", NULL
  345. };
  346. static int physmap_flash_pdata_init(struct platform_device *dev)
  347. {
  348. struct physmap_flash_info *info = platform_get_drvdata(dev);
  349. struct physmap_flash_data *physmap_data;
  350. unsigned int i;
  351. int err;
  352. physmap_data = dev_get_platdata(&dev->dev);
  353. if (!physmap_data)
  354. return -EINVAL;
  355. info->probe_type = physmap_data->probe_type;
  356. info->part_types = physmap_data->part_probe_types ? : part_probe_types;
  357. info->parts = physmap_data->parts;
  358. info->nparts = physmap_data->nr_parts;
  359. if (physmap_data->init) {
  360. err = physmap_data->init(dev);
  361. if (err)
  362. return err;
  363. }
  364. for (i = 0; i < info->nmaps; i++) {
  365. info->maps[i].bankwidth = physmap_data->width;
  366. info->maps[i].pfow_base = physmap_data->pfow_base;
  367. info->maps[i].set_vpp = physmap_set_vpp;
  368. }
  369. return 0;
  370. }
  371. static int physmap_flash_probe(struct platform_device *dev)
  372. {
  373. struct physmap_flash_info *info;
  374. int err = 0;
  375. int i;
  376. if (!dev->dev.of_node && !dev_get_platdata(&dev->dev))
  377. return -EINVAL;
  378. info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL);
  379. if (!info)
  380. return -ENOMEM;
  381. while (platform_get_resource(dev, IORESOURCE_MEM, info->nmaps))
  382. info->nmaps++;
  383. if (!info->nmaps)
  384. return -ENODEV;
  385. info->maps = devm_kzalloc(&dev->dev,
  386. sizeof(*info->maps) * info->nmaps,
  387. GFP_KERNEL);
  388. if (!info->maps)
  389. return -ENOMEM;
  390. info->mtds = devm_kzalloc(&dev->dev,
  391. sizeof(*info->mtds) * info->nmaps,
  392. GFP_KERNEL);
  393. if (!info->mtds)
  394. return -ENOMEM;
  395. platform_set_drvdata(dev, info);
  396. info->gpios = devm_gpiod_get_array_optional(&dev->dev, "addr",
  397. GPIOD_OUT_LOW);
  398. if (IS_ERR(info->gpios))
  399. return PTR_ERR(info->gpios);
  400. if (info->gpios && info->nmaps > 1) {
  401. dev_err(&dev->dev, "addr-gpios only supported for nmaps == 1\n");
  402. return -EINVAL;
  403. }
  404. pm_runtime_enable(&dev->dev);
  405. pm_runtime_get_sync(&dev->dev);
  406. if (dev->dev.of_node)
  407. err = physmap_flash_of_init(dev);
  408. else
  409. err = physmap_flash_pdata_init(dev);
  410. if (err) {
  411. pm_runtime_put(&dev->dev);
  412. pm_runtime_disable(&dev->dev);
  413. return err;
  414. }
  415. for (i = 0; i < info->nmaps; i++) {
  416. struct resource *res;
  417. info->maps[i].virt = devm_platform_get_and_ioremap_resource(dev, i, &res);
  418. if (IS_ERR(info->maps[i].virt)) {
  419. err = PTR_ERR(info->maps[i].virt);
  420. goto err_out;
  421. }
  422. dev_notice(&dev->dev, "physmap platform flash device: %pR\n",
  423. res);
  424. if (!info->maps[i].name)
  425. info->maps[i].name = dev_name(&dev->dev);
  426. if (!info->maps[i].phys)
  427. info->maps[i].phys = res->start;
  428. info->win_order = fls64(resource_size(res)) - 1;
  429. info->maps[i].size = BIT(info->win_order +
  430. (info->gpios ?
  431. info->gpios->ndescs : 0));
  432. info->maps[i].map_priv_1 = (unsigned long)dev;
  433. if (info->gpios) {
  434. err = physmap_addr_gpios_map_init(&info->maps[i]);
  435. if (err)
  436. goto err_out;
  437. }
  438. #ifdef CONFIG_MTD_COMPLEX_MAPPINGS
  439. /*
  440. * Only use the simple_map implementation if map hooks are not
  441. * implemented. Since map->read() is mandatory checking for its
  442. * presence is enough.
  443. */
  444. if (!info->maps[i].read)
  445. simple_map_init(&info->maps[i]);
  446. #else
  447. simple_map_init(&info->maps[i]);
  448. #endif
  449. if (info->probe_type) {
  450. info->mtds[i] = do_map_probe(info->probe_type,
  451. &info->maps[i]);
  452. /* Fall back to mapping region as ROM */
  453. if (!info->mtds[i] && IS_ENABLED(CONFIG_MTD_ROM) &&
  454. strcmp(info->probe_type, "map_rom")) {
  455. dev_warn(&dev->dev,
  456. "map_probe() failed for type %s\n",
  457. info->probe_type);
  458. info->mtds[i] = do_map_probe("map_rom",
  459. &info->maps[i]);
  460. }
  461. } else {
  462. int j;
  463. for (j = 0; j < ARRAY_SIZE(rom_probe_types); j++) {
  464. info->mtds[i] = do_map_probe(rom_probe_types[j],
  465. &info->maps[i]);
  466. if (info->mtds[i])
  467. break;
  468. }
  469. }
  470. if (!info->mtds[i]) {
  471. dev_err(&dev->dev, "map_probe failed\n");
  472. err = -ENXIO;
  473. goto err_out;
  474. }
  475. info->mtds[i]->dev.parent = &dev->dev;
  476. }
  477. if (info->nmaps == 1) {
  478. info->cmtd = info->mtds[0];
  479. } else {
  480. /*
  481. * We detected multiple devices. Concatenate them together.
  482. */
  483. info->cmtd = mtd_concat_create(info->mtds, info->nmaps,
  484. dev_name(&dev->dev));
  485. if (!info->cmtd)
  486. err = -ENXIO;
  487. }
  488. if (err)
  489. goto err_out;
  490. spin_lock_init(&info->vpp_lock);
  491. mtd_set_of_node(info->cmtd, dev->dev.of_node);
  492. err = mtd_device_parse_register(info->cmtd, info->part_types, NULL,
  493. info->parts, info->nparts);
  494. if (err)
  495. goto err_out;
  496. return 0;
  497. err_out:
  498. physmap_flash_remove(dev);
  499. return err;
  500. }
  501. #ifdef CONFIG_PM
  502. static void physmap_flash_shutdown(struct platform_device *dev)
  503. {
  504. struct physmap_flash_info *info = platform_get_drvdata(dev);
  505. int i;
  506. for (i = 0; i < info->nmaps && info->mtds[i]; i++)
  507. if (mtd_suspend(info->mtds[i]) == 0)
  508. mtd_resume(info->mtds[i]);
  509. }
  510. #else
  511. #define physmap_flash_shutdown NULL
  512. #endif
  513. static struct platform_driver physmap_flash_driver = {
  514. .probe = physmap_flash_probe,
  515. .remove = physmap_flash_remove,
  516. .shutdown = physmap_flash_shutdown,
  517. .driver = {
  518. .name = "physmap-flash",
  519. .of_match_table = of_flash_match,
  520. },
  521. };
  522. #ifdef CONFIG_MTD_PHYSMAP_COMPAT
  523. static struct physmap_flash_data physmap_flash_data = {
  524. .width = CONFIG_MTD_PHYSMAP_BANKWIDTH,
  525. };
  526. static struct resource physmap_flash_resource = {
  527. .start = CONFIG_MTD_PHYSMAP_START,
  528. .end = CONFIG_MTD_PHYSMAP_START + CONFIG_MTD_PHYSMAP_LEN - 1,
  529. .flags = IORESOURCE_MEM,
  530. };
  531. static struct platform_device physmap_flash = {
  532. .name = "physmap-flash",
  533. .id = 0,
  534. .dev = {
  535. .platform_data = &physmap_flash_data,
  536. },
  537. .num_resources = 1,
  538. .resource = &physmap_flash_resource,
  539. };
  540. #endif
  541. static int __init physmap_init(void)
  542. {
  543. int err;
  544. err = platform_driver_register(&physmap_flash_driver);
  545. #ifdef CONFIG_MTD_PHYSMAP_COMPAT
  546. if (err == 0) {
  547. err = platform_device_register(&physmap_flash);
  548. if (err)
  549. platform_driver_unregister(&physmap_flash_driver);
  550. }
  551. #endif
  552. return err;
  553. }
  554. static void __exit physmap_exit(void)
  555. {
  556. #ifdef CONFIG_MTD_PHYSMAP_COMPAT
  557. platform_device_unregister(&physmap_flash);
  558. #endif
  559. platform_driver_unregister(&physmap_flash_driver);
  560. }
  561. module_init(physmap_init);
  562. module_exit(physmap_exit);
  563. MODULE_LICENSE("GPL");
  564. MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
  565. MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
  566. MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
  567. MODULE_DESCRIPTION("Generic configurable MTD map driver");
  568. /* legacy platform drivers can't hotplug or coldplg */
  569. #ifndef CONFIG_MTD_PHYSMAP_COMPAT
  570. /* work with hotplug and coldplug */
  571. MODULE_ALIAS("platform:physmap-flash");
  572. #endif