diff options
Diffstat (limited to 'drivers/mtd/nand/omap2.c')
-rw-r--r-- | drivers/mtd/nand/omap2.c | 642 |
1 files changed, 285 insertions, 357 deletions
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 4ecf0e5fd484..f77725009907 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c | |||
@@ -25,10 +25,8 @@ | |||
25 | #include <linux/of.h> | 25 | #include <linux/of.h> |
26 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
27 | 27 | ||
28 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | 28 | #include <linux/mtd/nand_bch.h> |
29 | #include <linux/bch.h> | ||
30 | #include <linux/platform_data/elm.h> | 29 | #include <linux/platform_data/elm.h> |
31 | #endif | ||
32 | 30 | ||
33 | #include <linux/platform_data/mtd-nand-omap2.h> | 31 | #include <linux/platform_data/mtd-nand-omap2.h> |
34 | 32 | ||
@@ -141,6 +139,8 @@ | |||
141 | #define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */ | 139 | #define BCH_ECC_SIZE0 0x0 /* ecc_size0 = 0, no oob protection */ |
142 | #define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */ | 140 | #define BCH_ECC_SIZE1 0x20 /* ecc_size1 = 32 */ |
143 | 141 | ||
142 | #define BADBLOCK_MARKER_LENGTH 2 | ||
143 | |||
144 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | 144 | #ifdef CONFIG_MTD_NAND_OMAP_BCH |
145 | static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, | 145 | static u_char bch8_vector[] = {0xf3, 0xdb, 0x14, 0x16, 0x8b, 0xd2, 0xbe, 0xcc, |
146 | 0xac, 0x6b, 0xff, 0x99, 0x7b}; | 146 | 0xac, 0x6b, 0xff, 0x99, 0x7b}; |
@@ -149,17 +149,6 @@ static u_char bch4_vector[] = {0x00, 0x6b, 0x31, 0xdd, 0x41, 0xbc, 0x10}; | |||
149 | 149 | ||
150 | /* oob info generated runtime depending on ecc algorithm and layout selected */ | 150 | /* oob info generated runtime depending on ecc algorithm and layout selected */ |
151 | static struct nand_ecclayout omap_oobinfo; | 151 | static struct nand_ecclayout omap_oobinfo; |
152 | /* Define some generic bad / good block scan pattern which are used | ||
153 | * while scanning a device for factory marked good / bad blocks | ||
154 | */ | ||
155 | static uint8_t scan_ff_pattern[] = { 0xff }; | ||
156 | static struct nand_bbt_descr bb_descrip_flashbased = { | ||
157 | .options = NAND_BBT_SCANALLPAGES, | ||
158 | .offs = 0, | ||
159 | .len = 1, | ||
160 | .pattern = scan_ff_pattern, | ||
161 | }; | ||
162 | |||
163 | 152 | ||
164 | struct omap_nand_info { | 153 | struct omap_nand_info { |
165 | struct nand_hw_control controller; | 154 | struct nand_hw_control controller; |
@@ -182,14 +171,10 @@ struct omap_nand_info { | |||
182 | u_char *buf; | 171 | u_char *buf; |
183 | int buf_len; | 172 | int buf_len; |
184 | struct gpmc_nand_regs reg; | 173 | struct gpmc_nand_regs reg; |
185 | 174 | /* fields specific for BCHx_HW ECC scheme */ | |
186 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
187 | struct bch_control *bch; | ||
188 | struct nand_ecclayout ecclayout; | ||
189 | bool is_elm_used; | 175 | bool is_elm_used; |
190 | struct device *elm_dev; | 176 | struct device *elm_dev; |
191 | struct device_node *of_node; | 177 | struct device_node *of_node; |
192 | #endif | ||
193 | }; | 178 | }; |
194 | 179 | ||
195 | /** | 180 | /** |
@@ -1058,8 +1043,7 @@ static int omap_dev_ready(struct mtd_info *mtd) | |||
1058 | } | 1043 | } |
1059 | } | 1044 | } |
1060 | 1045 | ||
1061 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | 1046 | #if defined(CONFIG_MTD_NAND_ECC_BCH) || defined(CONFIG_MTD_NAND_OMAP_BCH) |
1062 | |||
1063 | /** | 1047 | /** |
1064 | * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction | 1048 | * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction |
1065 | * @mtd: MTD device structure | 1049 | * @mtd: MTD device structure |
@@ -1140,7 +1124,9 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode) | |||
1140 | /* Clear ecc and enable bits */ | 1124 | /* Clear ecc and enable bits */ |
1141 | writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); | 1125 | writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control); |
1142 | } | 1126 | } |
1127 | #endif | ||
1143 | 1128 | ||
1129 | #ifdef CONFIG_MTD_NAND_ECC_BCH | ||
1144 | /** | 1130 | /** |
1145 | * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes | 1131 | * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes |
1146 | * @mtd: MTD device structure | 1132 | * @mtd: MTD device structure |
@@ -1225,7 +1211,9 @@ static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat, | |||
1225 | 1211 | ||
1226 | return 0; | 1212 | return 0; |
1227 | } | 1213 | } |
1214 | #endif /* CONFIG_MTD_NAND_ECC_BCH */ | ||
1228 | 1215 | ||
1216 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
1229 | /** | 1217 | /** |
1230 | * omap3_calculate_ecc_bch - Generate bytes of ECC bytes | 1218 | * omap3_calculate_ecc_bch - Generate bytes of ECC bytes |
1231 | * @mtd: MTD device structure | 1219 | * @mtd: MTD device structure |
@@ -1519,38 +1507,6 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data, | |||
1519 | } | 1507 | } |
1520 | 1508 | ||
1521 | /** | 1509 | /** |
1522 | * omap3_correct_data_bch - Decode received data and correct errors | ||
1523 | * @mtd: MTD device structure | ||
1524 | * @data: page data | ||
1525 | * @read_ecc: ecc read from nand flash | ||
1526 | * @calc_ecc: ecc read from HW ECC registers | ||
1527 | */ | ||
1528 | static int omap3_correct_data_bch(struct mtd_info *mtd, u_char *data, | ||
1529 | u_char *read_ecc, u_char *calc_ecc) | ||
1530 | { | ||
1531 | int i, count; | ||
1532 | /* cannot correct more than 8 errors */ | ||
1533 | unsigned int errloc[8]; | ||
1534 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
1535 | mtd); | ||
1536 | |||
1537 | count = decode_bch(info->bch, NULL, 512, read_ecc, calc_ecc, NULL, | ||
1538 | errloc); | ||
1539 | if (count > 0) { | ||
1540 | /* correct errors */ | ||
1541 | for (i = 0; i < count; i++) { | ||
1542 | /* correct data only, not ecc bytes */ | ||
1543 | if (errloc[i] < 8*512) | ||
1544 | data[errloc[i]/8] ^= 1 << (errloc[i] & 7); | ||
1545 | pr_debug("corrected bitflip %u\n", errloc[i]); | ||
1546 | } | ||
1547 | } else if (count < 0) { | ||
1548 | pr_err("ecc unrecoverable error\n"); | ||
1549 | } | ||
1550 | return count; | ||
1551 | } | ||
1552 | |||
1553 | /** | ||
1554 | * omap_write_page_bch - BCH ecc based write page function for entire page | 1510 | * omap_write_page_bch - BCH ecc based write page function for entire page |
1555 | * @mtd: mtd info structure | 1511 | * @mtd: mtd info structure |
1556 | * @chip: nand chip info structure | 1512 | * @chip: nand chip info structure |
@@ -1637,197 +1593,46 @@ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, | |||
1637 | } | 1593 | } |
1638 | 1594 | ||
1639 | /** | 1595 | /** |
1640 | * omap3_free_bch - Release BCH ecc resources | 1596 | * is_elm_present - checks for presence of ELM module by scanning DT nodes |
1641 | * @mtd: MTD device structure | 1597 | * @omap_nand_info: NAND device structure containing platform data |
1642 | */ | 1598 | * @bch_type: 0x0=BCH4, 0x1=BCH8, 0x2=BCH16 |
1643 | static void omap3_free_bch(struct mtd_info *mtd) | ||
1644 | { | ||
1645 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
1646 | mtd); | ||
1647 | if (info->bch) { | ||
1648 | free_bch(info->bch); | ||
1649 | info->bch = NULL; | ||
1650 | } | ||
1651 | } | ||
1652 | |||
1653 | /** | ||
1654 | * omap3_init_bch - Initialize BCH ECC | ||
1655 | * @mtd: MTD device structure | ||
1656 | * @ecc_opt: OMAP ECC mode (OMAP_ECC_BCH4_CODE_HW or OMAP_ECC_BCH8_CODE_HW) | ||
1657 | */ | ||
1658 | static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) | ||
1659 | { | ||
1660 | int max_errors; | ||
1661 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | ||
1662 | mtd); | ||
1663 | #ifdef CONFIG_MTD_NAND_OMAP_BCH8 | ||
1664 | const int hw_errors = BCH8_MAX_ERROR; | ||
1665 | #else | ||
1666 | const int hw_errors = BCH4_MAX_ERROR; | ||
1667 | #endif | ||
1668 | enum bch_ecc bch_type; | ||
1669 | const __be32 *parp; | ||
1670 | int lenp; | ||
1671 | struct device_node *elm_node; | ||
1672 | |||
1673 | info->bch = NULL; | ||
1674 | |||
1675 | max_errors = (ecc_opt == OMAP_ECC_BCH8_CODE_HW) ? | ||
1676 | BCH8_MAX_ERROR : BCH4_MAX_ERROR; | ||
1677 | if (max_errors != hw_errors) { | ||
1678 | pr_err("cannot configure %d-bit BCH ecc, only %d-bit supported", | ||
1679 | max_errors, hw_errors); | ||
1680 | goto fail; | ||
1681 | } | ||
1682 | |||
1683 | info->nand.ecc.size = 512; | ||
1684 | info->nand.ecc.hwctl = omap3_enable_hwecc_bch; | ||
1685 | info->nand.ecc.mode = NAND_ECC_HW; | ||
1686 | info->nand.ecc.strength = max_errors; | ||
1687 | |||
1688 | if (hw_errors == BCH8_MAX_ERROR) | ||
1689 | bch_type = BCH8_ECC; | ||
1690 | else | ||
1691 | bch_type = BCH4_ECC; | ||
1692 | |||
1693 | /* Detect availability of ELM module */ | ||
1694 | parp = of_get_property(info->of_node, "elm_id", &lenp); | ||
1695 | if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) { | ||
1696 | pr_err("Missing elm_id property, fall back to Software BCH\n"); | ||
1697 | info->is_elm_used = false; | ||
1698 | } else { | ||
1699 | struct platform_device *pdev; | ||
1700 | |||
1701 | elm_node = of_find_node_by_phandle(be32_to_cpup(parp)); | ||
1702 | pdev = of_find_device_by_node(elm_node); | ||
1703 | info->elm_dev = &pdev->dev; | ||
1704 | |||
1705 | if (elm_config(info->elm_dev, bch_type) == 0) | ||
1706 | info->is_elm_used = true; | ||
1707 | } | ||
1708 | |||
1709 | if (info->is_elm_used && (mtd->writesize <= 4096)) { | ||
1710 | |||
1711 | if (hw_errors == BCH8_MAX_ERROR) | ||
1712 | info->nand.ecc.bytes = BCH8_SIZE; | ||
1713 | else | ||
1714 | info->nand.ecc.bytes = BCH4_SIZE; | ||
1715 | |||
1716 | info->nand.ecc.correct = omap_elm_correct_data; | ||
1717 | info->nand.ecc.calculate = omap3_calculate_ecc_bch; | ||
1718 | info->nand.ecc.read_page = omap_read_page_bch; | ||
1719 | info->nand.ecc.write_page = omap_write_page_bch; | ||
1720 | } else { | ||
1721 | /* | ||
1722 | * software bch library is only used to detect and | ||
1723 | * locate errors | ||
1724 | */ | ||
1725 | info->bch = init_bch(13, max_errors, | ||
1726 | 0x201b /* hw polynomial */); | ||
1727 | if (!info->bch) | ||
1728 | goto fail; | ||
1729 | |||
1730 | info->nand.ecc.correct = omap3_correct_data_bch; | ||
1731 | |||
1732 | /* | ||
1733 | * The number of corrected errors in an ecc block that will | ||
1734 | * trigger block scrubbing defaults to the ecc strength (4 or 8) | ||
1735 | * Set mtd->bitflip_threshold here to define a custom threshold. | ||
1736 | */ | ||
1737 | |||
1738 | if (max_errors == 8) { | ||
1739 | info->nand.ecc.bytes = 13; | ||
1740 | info->nand.ecc.calculate = omap3_calculate_ecc_bch8; | ||
1741 | } else { | ||
1742 | info->nand.ecc.bytes = 7; | ||
1743 | info->nand.ecc.calculate = omap3_calculate_ecc_bch4; | ||
1744 | } | ||
1745 | } | ||
1746 | |||
1747 | pr_info("enabling NAND BCH ecc with %d-bit correction\n", max_errors); | ||
1748 | return 0; | ||
1749 | fail: | ||
1750 | omap3_free_bch(mtd); | ||
1751 | return -1; | ||
1752 | } | ||
1753 | |||
1754 | /** | ||
1755 | * omap3_init_bch_tail - Build an oob layout for BCH ECC correction. | ||
1756 | * @mtd: MTD device structure | ||
1757 | */ | 1599 | */ |
1758 | static int omap3_init_bch_tail(struct mtd_info *mtd) | 1600 | static int is_elm_present(struct omap_nand_info *info, |
1601 | struct device_node *elm_node, enum bch_ecc bch_type) | ||
1759 | { | 1602 | { |
1760 | int i, steps, offset; | 1603 | struct platform_device *pdev; |
1761 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 1604 | info->is_elm_used = false; |
1762 | mtd); | 1605 | /* check whether elm-id is passed via DT */ |
1763 | struct nand_ecclayout *layout = &info->ecclayout; | 1606 | if (!elm_node) { |
1764 | 1607 | pr_err("nand: error: ELM DT node not found\n"); | |
1765 | /* build oob layout */ | 1608 | return -ENODEV; |
1766 | steps = mtd->writesize/info->nand.ecc.size; | ||
1767 | layout->eccbytes = steps*info->nand.ecc.bytes; | ||
1768 | |||
1769 | /* do not bother creating special oob layouts for small page devices */ | ||
1770 | if (mtd->oobsize < 64) { | ||
1771 | pr_err("BCH ecc is not supported on small page devices\n"); | ||
1772 | goto fail; | ||
1773 | } | 1609 | } |
1774 | 1610 | pdev = of_find_device_by_node(elm_node); | |
1775 | /* reserve 2 bytes for bad block marker */ | 1611 | /* check whether ELM device is registered */ |
1776 | if (layout->eccbytes+2 > mtd->oobsize) { | 1612 | if (!pdev) { |
1777 | pr_err("no oob layout available for oobsize %d eccbytes %u\n", | 1613 | pr_err("nand: error: ELM device not found\n"); |
1778 | mtd->oobsize, layout->eccbytes); | 1614 | return -ENODEV; |
1779 | goto fail; | ||
1780 | } | 1615 | } |
1781 | 1616 | /* ELM module available, now configure it */ | |
1782 | /* ECC layout compatible with RBL for BCH8 */ | 1617 | info->elm_dev = &pdev->dev; |
1783 | if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE)) | 1618 | if (elm_config(info->elm_dev, bch_type)) |
1784 | offset = 2; | 1619 | return -ENODEV; |
1785 | else | 1620 | info->is_elm_used = true; |
1786 | offset = mtd->oobsize - layout->eccbytes; | ||
1787 | |||
1788 | /* put ecc bytes at oob tail */ | ||
1789 | for (i = 0; i < layout->eccbytes; i++) | ||
1790 | layout->eccpos[i] = offset + i; | ||
1791 | |||
1792 | if (info->is_elm_used && (info->nand.ecc.bytes == BCH8_SIZE)) | ||
1793 | layout->oobfree[0].offset = 2 + layout->eccbytes * steps; | ||
1794 | else | ||
1795 | layout->oobfree[0].offset = 2; | ||
1796 | |||
1797 | layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes; | ||
1798 | info->nand.ecc.layout = layout; | ||
1799 | |||
1800 | if (!(info->nand.options & NAND_BUSWIDTH_16)) | ||
1801 | info->nand.badblock_pattern = &bb_descrip_flashbased; | ||
1802 | return 0; | 1621 | return 0; |
1803 | fail: | ||
1804 | omap3_free_bch(mtd); | ||
1805 | return -1; | ||
1806 | } | ||
1807 | |||
1808 | #else | ||
1809 | static int omap3_init_bch(struct mtd_info *mtd, int ecc_opt) | ||
1810 | { | ||
1811 | pr_err("CONFIG_MTD_NAND_OMAP_BCH is not enabled\n"); | ||
1812 | return -1; | ||
1813 | } | ||
1814 | static int omap3_init_bch_tail(struct mtd_info *mtd) | ||
1815 | { | ||
1816 | return -1; | ||
1817 | } | ||
1818 | static void omap3_free_bch(struct mtd_info *mtd) | ||
1819 | { | ||
1820 | } | 1622 | } |
1821 | #endif /* CONFIG_MTD_NAND_OMAP_BCH */ | 1623 | #endif /* CONFIG_MTD_NAND_ECC_BCH */ |
1822 | 1624 | ||
1823 | static int omap_nand_probe(struct platform_device *pdev) | 1625 | static int omap_nand_probe(struct platform_device *pdev) |
1824 | { | 1626 | { |
1825 | struct omap_nand_info *info; | 1627 | struct omap_nand_info *info; |
1826 | struct omap_nand_platform_data *pdata; | 1628 | struct omap_nand_platform_data *pdata; |
1629 | struct mtd_info *mtd; | ||
1630 | struct nand_chip *nand_chip; | ||
1631 | struct nand_ecclayout *ecclayout; | ||
1827 | int err; | 1632 | int err; |
1828 | int i, offset; | 1633 | int i; |
1829 | dma_cap_mask_t mask; | 1634 | dma_cap_mask_t mask; |
1830 | unsigned sig; | 1635 | unsigned sig; |
1831 | struct resource *res; | 1636 | struct resource *res; |
1832 | struct mtd_part_parser_data ppdata = {}; | 1637 | struct mtd_part_parser_data ppdata = {}; |
1833 | 1638 | ||
@@ -1837,7 +1642,8 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1837 | return -ENODEV; | 1642 | return -ENODEV; |
1838 | } | 1643 | } |
1839 | 1644 | ||
1840 | info = kzalloc(sizeof(struct omap_nand_info), GFP_KERNEL); | 1645 | info = devm_kzalloc(&pdev->dev, sizeof(struct omap_nand_info), |
1646 | GFP_KERNEL); | ||
1841 | if (!info) | 1647 | if (!info) |
1842 | return -ENOMEM; | 1648 | return -ENOMEM; |
1843 | 1649 | ||
@@ -1846,47 +1652,45 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1846 | spin_lock_init(&info->controller.lock); | 1652 | spin_lock_init(&info->controller.lock); |
1847 | init_waitqueue_head(&info->controller.wq); | 1653 | init_waitqueue_head(&info->controller.wq); |
1848 | 1654 | ||
1849 | info->pdev = pdev; | 1655 | info->pdev = pdev; |
1850 | |||
1851 | info->gpmc_cs = pdata->cs; | 1656 | info->gpmc_cs = pdata->cs; |
1852 | info->reg = pdata->reg; | 1657 | info->reg = pdata->reg; |
1853 | |||
1854 | info->mtd.priv = &info->nand; | ||
1855 | info->mtd.name = dev_name(&pdev->dev); | ||
1856 | info->mtd.owner = THIS_MODULE; | ||
1857 | |||
1858 | info->nand.options = pdata->devsize; | ||
1859 | info->nand.options |= NAND_SKIP_BBTSCAN; | ||
1860 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
1861 | info->of_node = pdata->of_node; | 1658 | info->of_node = pdata->of_node; |
1862 | #endif | 1659 | mtd = &info->mtd; |
1660 | mtd->priv = &info->nand; | ||
1661 | mtd->name = dev_name(&pdev->dev); | ||
1662 | mtd->owner = THIS_MODULE; | ||
1663 | nand_chip = &info->nand; | ||
1664 | nand_chip->ecc.priv = NULL; | ||
1665 | nand_chip->options |= NAND_SKIP_BBTSCAN; | ||
1863 | 1666 | ||
1864 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1667 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1865 | if (res == NULL) { | 1668 | if (res == NULL) { |
1866 | err = -EINVAL; | 1669 | err = -EINVAL; |
1867 | dev_err(&pdev->dev, "error getting memory resource\n"); | 1670 | dev_err(&pdev->dev, "error getting memory resource\n"); |
1868 | goto out_free_info; | 1671 | goto return_error; |
1869 | } | 1672 | } |
1870 | 1673 | ||
1871 | info->phys_base = res->start; | 1674 | info->phys_base = res->start; |
1872 | info->mem_size = resource_size(res); | 1675 | info->mem_size = resource_size(res); |
1873 | 1676 | ||
1874 | if (!request_mem_region(info->phys_base, info->mem_size, | 1677 | if (!devm_request_mem_region(&pdev->dev, info->phys_base, |
1875 | pdev->dev.driver->name)) { | 1678 | info->mem_size, pdev->dev.driver->name)) { |
1876 | err = -EBUSY; | 1679 | err = -EBUSY; |
1877 | goto out_free_info; | 1680 | goto return_error; |
1878 | } | 1681 | } |
1879 | 1682 | ||
1880 | info->nand.IO_ADDR_R = ioremap(info->phys_base, info->mem_size); | 1683 | nand_chip->IO_ADDR_R = devm_ioremap(&pdev->dev, info->phys_base, |
1881 | if (!info->nand.IO_ADDR_R) { | 1684 | info->mem_size); |
1685 | if (!nand_chip->IO_ADDR_R) { | ||
1882 | err = -ENOMEM; | 1686 | err = -ENOMEM; |
1883 | goto out_release_mem_region; | 1687 | goto return_error; |
1884 | } | 1688 | } |
1885 | 1689 | ||
1886 | info->nand.controller = &info->controller; | 1690 | nand_chip->controller = &info->controller; |
1887 | 1691 | ||
1888 | info->nand.IO_ADDR_W = info->nand.IO_ADDR_R; | 1692 | nand_chip->IO_ADDR_W = nand_chip->IO_ADDR_R; |
1889 | info->nand.cmd_ctrl = omap_hwcontrol; | 1693 | nand_chip->cmd_ctrl = omap_hwcontrol; |
1890 | 1694 | ||
1891 | /* | 1695 | /* |
1892 | * If RDY/BSY line is connected to OMAP then use the omap ready | 1696 | * If RDY/BSY line is connected to OMAP then use the omap ready |
@@ -1896,26 +1700,42 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1896 | * device and read status register until you get a failure or success | 1700 | * device and read status register until you get a failure or success |
1897 | */ | 1701 | */ |
1898 | if (pdata->dev_ready) { | 1702 | if (pdata->dev_ready) { |
1899 | info->nand.dev_ready = omap_dev_ready; | 1703 | nand_chip->dev_ready = omap_dev_ready; |
1900 | info->nand.chip_delay = 0; | 1704 | nand_chip->chip_delay = 0; |
1901 | } else { | 1705 | } else { |
1902 | info->nand.waitfunc = omap_wait; | 1706 | nand_chip->waitfunc = omap_wait; |
1903 | info->nand.chip_delay = 50; | 1707 | nand_chip->chip_delay = 50; |
1904 | } | 1708 | } |
1905 | 1709 | ||
1710 | /* scan NAND device connected to chip controller */ | ||
1711 | nand_chip->options |= pdata->devsize & NAND_BUSWIDTH_16; | ||
1712 | if (nand_scan_ident(mtd, 1, NULL)) { | ||
1713 | pr_err("nand device scan failed, may be bus-width mismatch\n"); | ||
1714 | err = -ENXIO; | ||
1715 | goto return_error; | ||
1716 | } | ||
1717 | |||
1718 | /* check for small page devices */ | ||
1719 | if ((mtd->oobsize < 64) && (pdata->ecc_opt != OMAP_ECC_HAM1_CODE_HW)) { | ||
1720 | pr_err("small page devices are not supported\n"); | ||
1721 | err = -EINVAL; | ||
1722 | goto return_error; | ||
1723 | } | ||
1724 | |||
1725 | /* re-populate low-level callbacks based on xfer modes */ | ||
1906 | switch (pdata->xfer_type) { | 1726 | switch (pdata->xfer_type) { |
1907 | case NAND_OMAP_PREFETCH_POLLED: | 1727 | case NAND_OMAP_PREFETCH_POLLED: |
1908 | info->nand.read_buf = omap_read_buf_pref; | 1728 | nand_chip->read_buf = omap_read_buf_pref; |
1909 | info->nand.write_buf = omap_write_buf_pref; | 1729 | nand_chip->write_buf = omap_write_buf_pref; |
1910 | break; | 1730 | break; |
1911 | 1731 | ||
1912 | case NAND_OMAP_POLLED: | 1732 | case NAND_OMAP_POLLED: |
1913 | if (info->nand.options & NAND_BUSWIDTH_16) { | 1733 | if (nand_chip->options & NAND_BUSWIDTH_16) { |
1914 | info->nand.read_buf = omap_read_buf16; | 1734 | nand_chip->read_buf = omap_read_buf16; |
1915 | info->nand.write_buf = omap_write_buf16; | 1735 | nand_chip->write_buf = omap_write_buf16; |
1916 | } else { | 1736 | } else { |
1917 | info->nand.read_buf = omap_read_buf8; | 1737 | nand_chip->read_buf = omap_read_buf8; |
1918 | info->nand.write_buf = omap_write_buf8; | 1738 | nand_chip->write_buf = omap_write_buf8; |
1919 | } | 1739 | } |
1920 | break; | 1740 | break; |
1921 | 1741 | ||
@@ -1927,7 +1747,7 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1927 | if (!info->dma) { | 1747 | if (!info->dma) { |
1928 | dev_err(&pdev->dev, "DMA engine request failed\n"); | 1748 | dev_err(&pdev->dev, "DMA engine request failed\n"); |
1929 | err = -ENXIO; | 1749 | err = -ENXIO; |
1930 | goto out_release_mem_region; | 1750 | goto return_error; |
1931 | } else { | 1751 | } else { |
1932 | struct dma_slave_config cfg; | 1752 | struct dma_slave_config cfg; |
1933 | 1753 | ||
@@ -1942,10 +1762,10 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1942 | if (err) { | 1762 | if (err) { |
1943 | dev_err(&pdev->dev, "DMA engine slave config failed: %d\n", | 1763 | dev_err(&pdev->dev, "DMA engine slave config failed: %d\n", |
1944 | err); | 1764 | err); |
1945 | goto out_release_mem_region; | 1765 | goto return_error; |
1946 | } | 1766 | } |
1947 | info->nand.read_buf = omap_read_buf_dma_pref; | 1767 | nand_chip->read_buf = omap_read_buf_dma_pref; |
1948 | info->nand.write_buf = omap_write_buf_dma_pref; | 1768 | nand_chip->write_buf = omap_write_buf_dma_pref; |
1949 | } | 1769 | } |
1950 | break; | 1770 | break; |
1951 | 1771 | ||
@@ -1954,34 +1774,36 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1954 | if (info->gpmc_irq_fifo <= 0) { | 1774 | if (info->gpmc_irq_fifo <= 0) { |
1955 | dev_err(&pdev->dev, "error getting fifo irq\n"); | 1775 | dev_err(&pdev->dev, "error getting fifo irq\n"); |
1956 | err = -ENODEV; | 1776 | err = -ENODEV; |
1957 | goto out_release_mem_region; | 1777 | goto return_error; |
1958 | } | 1778 | } |
1959 | err = request_irq(info->gpmc_irq_fifo, omap_nand_irq, | 1779 | err = devm_request_irq(&pdev->dev, info->gpmc_irq_fifo, |
1960 | IRQF_SHARED, "gpmc-nand-fifo", info); | 1780 | omap_nand_irq, IRQF_SHARED, |
1781 | "gpmc-nand-fifo", info); | ||
1961 | if (err) { | 1782 | if (err) { |
1962 | dev_err(&pdev->dev, "requesting irq(%d) error:%d", | 1783 | dev_err(&pdev->dev, "requesting irq(%d) error:%d", |
1963 | info->gpmc_irq_fifo, err); | 1784 | info->gpmc_irq_fifo, err); |
1964 | info->gpmc_irq_fifo = 0; | 1785 | info->gpmc_irq_fifo = 0; |
1965 | goto out_release_mem_region; | 1786 | goto return_error; |
1966 | } | 1787 | } |
1967 | 1788 | ||
1968 | info->gpmc_irq_count = platform_get_irq(pdev, 1); | 1789 | info->gpmc_irq_count = platform_get_irq(pdev, 1); |
1969 | if (info->gpmc_irq_count <= 0) { | 1790 | if (info->gpmc_irq_count <= 0) { |
1970 | dev_err(&pdev->dev, "error getting count irq\n"); | 1791 | dev_err(&pdev->dev, "error getting count irq\n"); |
1971 | err = -ENODEV; | 1792 | err = -ENODEV; |
1972 | goto out_release_mem_region; | 1793 | goto return_error; |
1973 | } | 1794 | } |
1974 | err = request_irq(info->gpmc_irq_count, omap_nand_irq, | 1795 | err = devm_request_irq(&pdev->dev, info->gpmc_irq_count, |
1975 | IRQF_SHARED, "gpmc-nand-count", info); | 1796 | omap_nand_irq, IRQF_SHARED, |
1797 | "gpmc-nand-count", info); | ||
1976 | if (err) { | 1798 | if (err) { |
1977 | dev_err(&pdev->dev, "requesting irq(%d) error:%d", | 1799 | dev_err(&pdev->dev, "requesting irq(%d) error:%d", |
1978 | info->gpmc_irq_count, err); | 1800 | info->gpmc_irq_count, err); |
1979 | info->gpmc_irq_count = 0; | 1801 | info->gpmc_irq_count = 0; |
1980 | goto out_release_mem_region; | 1802 | goto return_error; |
1981 | } | 1803 | } |
1982 | 1804 | ||
1983 | info->nand.read_buf = omap_read_buf_irq_pref; | 1805 | nand_chip->read_buf = omap_read_buf_irq_pref; |
1984 | info->nand.write_buf = omap_write_buf_irq_pref; | 1806 | nand_chip->write_buf = omap_write_buf_irq_pref; |
1985 | 1807 | ||
1986 | break; | 1808 | break; |
1987 | 1809 | ||
@@ -1989,117 +1811,223 @@ static int omap_nand_probe(struct platform_device *pdev) | |||
1989 | dev_err(&pdev->dev, | 1811 | dev_err(&pdev->dev, |
1990 | "xfer_type(%d) not supported!\n", pdata->xfer_type); | 1812 | "xfer_type(%d) not supported!\n", pdata->xfer_type); |
1991 | err = -EINVAL; | 1813 | err = -EINVAL; |
1992 | goto out_release_mem_region; | 1814 | goto return_error; |
1993 | } | 1815 | } |
1994 | 1816 | ||
1995 | /* select the ecc type */ | 1817 | /* populate MTD interface based on ECC scheme */ |
1996 | if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_DEFAULT) | 1818 | nand_chip->ecc.layout = &omap_oobinfo; |
1997 | info->nand.ecc.mode = NAND_ECC_SOFT; | 1819 | ecclayout = &omap_oobinfo; |
1998 | else if ((pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW) || | 1820 | switch (pdata->ecc_opt) { |
1999 | (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)) { | 1821 | case OMAP_ECC_HAM1_CODE_HW: |
2000 | info->nand.ecc.bytes = 3; | 1822 | pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); |
2001 | info->nand.ecc.size = 512; | 1823 | nand_chip->ecc.mode = NAND_ECC_HW; |
2002 | info->nand.ecc.strength = 1; | 1824 | nand_chip->ecc.bytes = 3; |
2003 | info->nand.ecc.calculate = omap_calculate_ecc; | 1825 | nand_chip->ecc.size = 512; |
2004 | info->nand.ecc.hwctl = omap_enable_hwecc; | 1826 | nand_chip->ecc.strength = 1; |
2005 | info->nand.ecc.correct = omap_correct_data; | 1827 | nand_chip->ecc.calculate = omap_calculate_ecc; |
2006 | info->nand.ecc.mode = NAND_ECC_HW; | 1828 | nand_chip->ecc.hwctl = omap_enable_hwecc; |
2007 | } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || | 1829 | nand_chip->ecc.correct = omap_correct_data; |
2008 | (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { | 1830 | /* define ECC layout */ |
2009 | err = omap3_init_bch(&info->mtd, pdata->ecc_opt); | 1831 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
2010 | if (err) { | 1832 | (mtd->writesize / |
1833 | nand_chip->ecc.size); | ||
1834 | if (nand_chip->options & NAND_BUSWIDTH_16) | ||
1835 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | ||
1836 | else | ||
1837 | ecclayout->eccpos[0] = 1; | ||
1838 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | ||
1839 | ecclayout->eccbytes; | ||
1840 | break; | ||
1841 | |||
1842 | case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: | ||
1843 | #ifdef CONFIG_MTD_NAND_ECC_BCH | ||
1844 | pr_info("nand: using OMAP_ECC_BCH4_CODE_HW_DETECTION_SW\n"); | ||
1845 | nand_chip->ecc.mode = NAND_ECC_HW; | ||
1846 | nand_chip->ecc.size = 512; | ||
1847 | nand_chip->ecc.bytes = 7; | ||
1848 | nand_chip->ecc.strength = 4; | ||
1849 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; | ||
1850 | nand_chip->ecc.correct = nand_bch_correct_data; | ||
1851 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch4; | ||
1852 | /* define ECC layout */ | ||
1853 | ecclayout->eccbytes = nand_chip->ecc.bytes * | ||
1854 | (mtd->writesize / | ||
1855 | nand_chip->ecc.size); | ||
1856 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | ||
1857 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | ||
1858 | ecclayout->eccbytes; | ||
1859 | /* software bch library is used for locating errors */ | ||
1860 | nand_chip->ecc.priv = nand_bch_init(mtd, | ||
1861 | nand_chip->ecc.size, | ||
1862 | nand_chip->ecc.bytes, | ||
1863 | &nand_chip->ecc.layout); | ||
1864 | if (!nand_chip->ecc.priv) { | ||
1865 | pr_err("nand: error: unable to use s/w BCH library\n"); | ||
2011 | err = -EINVAL; | 1866 | err = -EINVAL; |
2012 | goto out_release_mem_region; | ||
2013 | } | 1867 | } |
2014 | } | 1868 | break; |
1869 | #else | ||
1870 | pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); | ||
1871 | err = -EINVAL; | ||
1872 | goto return_error; | ||
1873 | #endif | ||
2015 | 1874 | ||
2016 | /* DIP switches on some boards change between 8 and 16 bit | 1875 | case OMAP_ECC_BCH4_CODE_HW: |
2017 | * bus widths for flash. Try the other width if the first try fails. | 1876 | #ifdef CONFIG_MTD_NAND_OMAP_BCH |
2018 | */ | 1877 | pr_info("nand: using OMAP_ECC_BCH4_CODE_HW ECC scheme\n"); |
2019 | if (nand_scan_ident(&info->mtd, 1, NULL)) { | 1878 | nand_chip->ecc.mode = NAND_ECC_HW; |
2020 | info->nand.options ^= NAND_BUSWIDTH_16; | 1879 | nand_chip->ecc.size = 512; |
2021 | if (nand_scan_ident(&info->mtd, 1, NULL)) { | 1880 | /* 14th bit is kept reserved for ROM-code compatibility */ |
2022 | err = -ENXIO; | 1881 | nand_chip->ecc.bytes = 7 + 1; |
2023 | goto out_release_mem_region; | 1882 | nand_chip->ecc.strength = 4; |
1883 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; | ||
1884 | nand_chip->ecc.correct = omap_elm_correct_data; | ||
1885 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch; | ||
1886 | nand_chip->ecc.read_page = omap_read_page_bch; | ||
1887 | nand_chip->ecc.write_page = omap_write_page_bch; | ||
1888 | /* define ECC layout */ | ||
1889 | ecclayout->eccbytes = nand_chip->ecc.bytes * | ||
1890 | (mtd->writesize / | ||
1891 | nand_chip->ecc.size); | ||
1892 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | ||
1893 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | ||
1894 | ecclayout->eccbytes; | ||
1895 | /* This ECC scheme requires ELM H/W block */ | ||
1896 | if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { | ||
1897 | pr_err("nand: error: could not initialize ELM\n"); | ||
1898 | err = -ENODEV; | ||
1899 | goto return_error; | ||
2024 | } | 1900 | } |
2025 | } | 1901 | break; |
2026 | 1902 | #else | |
2027 | /* rom code layout */ | 1903 | pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); |
2028 | if (pdata->ecc_opt == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) { | 1904 | err = -EINVAL; |
1905 | goto return_error; | ||
1906 | #endif | ||
2029 | 1907 | ||
2030 | if (info->nand.options & NAND_BUSWIDTH_16) | 1908 | case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW: |
2031 | offset = 2; | 1909 | #ifdef CONFIG_MTD_NAND_ECC_BCH |
2032 | else { | 1910 | pr_info("nand: using OMAP_ECC_BCH8_CODE_HW_DETECTION_SW\n"); |
2033 | offset = 1; | 1911 | nand_chip->ecc.mode = NAND_ECC_HW; |
2034 | info->nand.badblock_pattern = &bb_descrip_flashbased; | 1912 | nand_chip->ecc.size = 512; |
2035 | } | 1913 | nand_chip->ecc.bytes = 13; |
2036 | omap_oobinfo.eccbytes = 3 * (info->mtd.oobsize/16); | 1914 | nand_chip->ecc.strength = 8; |
2037 | for (i = 0; i < omap_oobinfo.eccbytes; i++) | 1915 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; |
2038 | omap_oobinfo.eccpos[i] = i+offset; | 1916 | nand_chip->ecc.correct = nand_bch_correct_data; |
2039 | 1917 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch8; | |
2040 | omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes; | 1918 | /* define ECC layout */ |
2041 | omap_oobinfo.oobfree->length = info->mtd.oobsize - | 1919 | ecclayout->eccbytes = nand_chip->ecc.bytes * |
2042 | (offset + omap_oobinfo.eccbytes); | 1920 | (mtd->writesize / |
2043 | 1921 | nand_chip->ecc.size); | |
2044 | info->nand.ecc.layout = &omap_oobinfo; | 1922 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; |
2045 | } else if ((pdata->ecc_opt == OMAP_ECC_BCH4_CODE_HW) || | 1923 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + |
2046 | (pdata->ecc_opt == OMAP_ECC_BCH8_CODE_HW)) { | 1924 | ecclayout->eccbytes; |
2047 | /* build OOB layout for BCH ECC correction */ | 1925 | /* software bch library is used for locating errors */ |
2048 | err = omap3_init_bch_tail(&info->mtd); | 1926 | nand_chip->ecc.priv = nand_bch_init(mtd, |
2049 | if (err) { | 1927 | nand_chip->ecc.size, |
1928 | nand_chip->ecc.bytes, | ||
1929 | &nand_chip->ecc.layout); | ||
1930 | if (!nand_chip->ecc.priv) { | ||
1931 | pr_err("nand: error: unable to use s/w BCH library\n"); | ||
2050 | err = -EINVAL; | 1932 | err = -EINVAL; |
2051 | goto out_release_mem_region; | 1933 | goto return_error; |
1934 | } | ||
1935 | break; | ||
1936 | #else | ||
1937 | pr_err("nand: error: CONFIG_MTD_NAND_ECC_BCH not enabled\n"); | ||
1938 | err = -EINVAL; | ||
1939 | goto return_error; | ||
1940 | #endif | ||
1941 | |||
1942 | case OMAP_ECC_BCH8_CODE_HW: | ||
1943 | #ifdef CONFIG_MTD_NAND_OMAP_BCH | ||
1944 | pr_info("nand: using OMAP_ECC_BCH8_CODE_HW ECC scheme\n"); | ||
1945 | nand_chip->ecc.mode = NAND_ECC_HW; | ||
1946 | nand_chip->ecc.size = 512; | ||
1947 | /* 14th bit is kept reserved for ROM-code compatibility */ | ||
1948 | nand_chip->ecc.bytes = 13 + 1; | ||
1949 | nand_chip->ecc.strength = 8; | ||
1950 | nand_chip->ecc.hwctl = omap3_enable_hwecc_bch; | ||
1951 | nand_chip->ecc.correct = omap_elm_correct_data; | ||
1952 | nand_chip->ecc.calculate = omap3_calculate_ecc_bch; | ||
1953 | nand_chip->ecc.read_page = omap_read_page_bch; | ||
1954 | nand_chip->ecc.write_page = omap_write_page_bch; | ||
1955 | /* This ECC scheme requires ELM H/W block */ | ||
1956 | err = is_elm_present(info, pdata->elm_of_node, BCH8_ECC); | ||
1957 | if (err < 0) { | ||
1958 | pr_err("nand: error: could not initialize ELM\n"); | ||
1959 | goto return_error; | ||
2052 | } | 1960 | } |
1961 | /* define ECC layout */ | ||
1962 | ecclayout->eccbytes = nand_chip->ecc.bytes * | ||
1963 | (mtd->writesize / | ||
1964 | nand_chip->ecc.size); | ||
1965 | ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; | ||
1966 | ecclayout->oobfree->offset = ecclayout->eccpos[0] + | ||
1967 | ecclayout->eccbytes; | ||
1968 | break; | ||
1969 | #else | ||
1970 | pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); | ||
1971 | err = -EINVAL; | ||
1972 | goto return_error; | ||
1973 | #endif | ||
1974 | |||
1975 | default: | ||
1976 | pr_err("nand: error: invalid or unsupported ECC scheme\n"); | ||
1977 | err = -EINVAL; | ||
1978 | goto return_error; | ||
1979 | } | ||
1980 | |||
1981 | /* populate remaining ECC layout data */ | ||
1982 | ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH + | ||
1983 | ecclayout->eccbytes); | ||
1984 | for (i = 1; i < ecclayout->eccbytes; i++) | ||
1985 | ecclayout->eccpos[i] = ecclayout->eccpos[0] + i; | ||
1986 | /* check if NAND device's OOB is enough to store ECC signatures */ | ||
1987 | if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { | ||
1988 | pr_err("not enough OOB bytes required = %d, available=%d\n", | ||
1989 | ecclayout->eccbytes, mtd->oobsize); | ||
1990 | err = -EINVAL; | ||
1991 | goto return_error; | ||
2053 | } | 1992 | } |
2054 | 1993 | ||
2055 | /* second phase scan */ | 1994 | /* second phase scan */ |
2056 | if (nand_scan_tail(&info->mtd)) { | 1995 | if (nand_scan_tail(mtd)) { |
2057 | err = -ENXIO; | 1996 | err = -ENXIO; |
2058 | goto out_release_mem_region; | 1997 | goto return_error; |
2059 | } | 1998 | } |
2060 | 1999 | ||
2061 | ppdata.of_node = pdata->of_node; | 2000 | ppdata.of_node = pdata->of_node; |
2062 | mtd_device_parse_register(&info->mtd, NULL, &ppdata, pdata->parts, | 2001 | mtd_device_parse_register(mtd, NULL, &ppdata, pdata->parts, |
2063 | pdata->nr_parts); | 2002 | pdata->nr_parts); |
2064 | 2003 | ||
2065 | platform_set_drvdata(pdev, &info->mtd); | 2004 | platform_set_drvdata(pdev, mtd); |
2066 | 2005 | ||
2067 | return 0; | 2006 | return 0; |
2068 | 2007 | ||
2069 | out_release_mem_region: | 2008 | return_error: |
2070 | if (info->dma) | 2009 | if (info->dma) |
2071 | dma_release_channel(info->dma); | 2010 | dma_release_channel(info->dma); |
2072 | if (info->gpmc_irq_count > 0) | 2011 | if (nand_chip->ecc.priv) { |
2073 | free_irq(info->gpmc_irq_count, info); | 2012 | nand_bch_free(nand_chip->ecc.priv); |
2074 | if (info->gpmc_irq_fifo > 0) | 2013 | nand_chip->ecc.priv = NULL; |
2075 | free_irq(info->gpmc_irq_fifo, info); | 2014 | } |
2076 | release_mem_region(info->phys_base, info->mem_size); | ||
2077 | out_free_info: | ||
2078 | kfree(info); | ||
2079 | |||
2080 | return err; | 2015 | return err; |
2081 | } | 2016 | } |
2082 | 2017 | ||
2083 | static int omap_nand_remove(struct platform_device *pdev) | 2018 | static int omap_nand_remove(struct platform_device *pdev) |
2084 | { | 2019 | { |
2085 | struct mtd_info *mtd = platform_get_drvdata(pdev); | 2020 | struct mtd_info *mtd = platform_get_drvdata(pdev); |
2021 | struct nand_chip *nand_chip = mtd->priv; | ||
2086 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, | 2022 | struct omap_nand_info *info = container_of(mtd, struct omap_nand_info, |
2087 | mtd); | 2023 | mtd); |
2088 | omap3_free_bch(&info->mtd); | 2024 | if (nand_chip->ecc.priv) { |
2089 | 2025 | nand_bch_free(nand_chip->ecc.priv); | |
2026 | nand_chip->ecc.priv = NULL; | ||
2027 | } | ||
2090 | if (info->dma) | 2028 | if (info->dma) |
2091 | dma_release_channel(info->dma); | 2029 | dma_release_channel(info->dma); |
2092 | 2030 | nand_release(mtd); | |
2093 | if (info->gpmc_irq_count > 0) | ||
2094 | free_irq(info->gpmc_irq_count, info); | ||
2095 | if (info->gpmc_irq_fifo > 0) | ||
2096 | free_irq(info->gpmc_irq_fifo, info); | ||
2097 | |||
2098 | /* Release NAND device, its internal structures and partitions */ | ||
2099 | nand_release(&info->mtd); | ||
2100 | iounmap(info->nand.IO_ADDR_R); | ||
2101 | release_mem_region(info->phys_base, info->mem_size); | ||
2102 | kfree(info); | ||
2103 | return 0; | 2031 | return 0; |
2104 | } | 2032 | } |
2105 | 2033 | ||