diff options
| author | Bastian Hecht <hechtb@googlemail.com> | 2012-05-14 08:14:41 -0400 |
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-07-06 13:17:03 -0400 |
| commit | 3c7ea4eccfd2e209ba666d217a2993b8a084a429 (patch) | |
| tree | d473d603989efa810727bbe76c6e8fc9348149d5 | |
| parent | cb54751d7a706b4a068b798b97e8a815b99fa835 (diff) | |
mtd: sh_flctl: Add support for error IRQ
When the data transfer between the controller and the NAND chip fails,
we now get notified.
Signed-off-by: Bastian Hecht <hechtb@gmail.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
| -rw-r--r-- | drivers/mtd/nand/sh_flctl.c | 34 | ||||
| -rw-r--r-- | include/linux/mtd/sh_flctl.h | 9 |
2 files changed, 40 insertions, 3 deletions
diff --git a/drivers/mtd/nand/sh_flctl.c b/drivers/mtd/nand/sh_flctl.c index a5a60cac7e70..c835b136e7cb 100644 --- a/drivers/mtd/nand/sh_flctl.c +++ b/drivers/mtd/nand/sh_flctl.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
| 25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
| 26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
| 27 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/io.h> | 28 | #include <linux/io.h> |
| 28 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
| 29 | #include <linux/pm_runtime.h> | 30 | #include <linux/pm_runtime.h> |
| @@ -68,8 +69,8 @@ static struct nand_bbt_descr flctl_4secc_largepage = { | |||
| 68 | 69 | ||
| 69 | static void empty_fifo(struct sh_flctl *flctl) | 70 | static void empty_fifo(struct sh_flctl *flctl) |
| 70 | { | 71 | { |
| 71 | writel(0x000c0000, FLINTDMACR(flctl)); /* FIFO Clear */ | 72 | writel(flctl->flintdmacr_base | AC1CLR | AC0CLR, FLINTDMACR(flctl)); |
| 72 | writel(0x00000000, FLINTDMACR(flctl)); /* Clear Error flags */ | 73 | writel(flctl->flintdmacr_base, FLINTDMACR(flctl)); |
| 73 | } | 74 | } |
| 74 | 75 | ||
| 75 | static void start_translation(struct sh_flctl *flctl) | 76 | static void start_translation(struct sh_flctl *flctl) |
| @@ -839,6 +840,16 @@ static int flctl_chip_init_tail(struct mtd_info *mtd) | |||
| 839 | return 0; | 840 | return 0; |
| 840 | } | 841 | } |
| 841 | 842 | ||
| 843 | static irqreturn_t flctl_handle_flste(int irq, void *dev_id) | ||
| 844 | { | ||
| 845 | struct sh_flctl *flctl = dev_id; | ||
| 846 | |||
| 847 | dev_err(&flctl->pdev->dev, "flste irq: %x\n", readl(FLINTDMACR(flctl))); | ||
| 848 | writel(flctl->flintdmacr_base, FLINTDMACR(flctl)); | ||
| 849 | |||
| 850 | return IRQ_HANDLED; | ||
| 851 | } | ||
| 852 | |||
| 842 | static int __devinit flctl_probe(struct platform_device *pdev) | 853 | static int __devinit flctl_probe(struct platform_device *pdev) |
| 843 | { | 854 | { |
| 844 | struct resource *res; | 855 | struct resource *res; |
| @@ -847,6 +858,7 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
| 847 | struct nand_chip *nand; | 858 | struct nand_chip *nand; |
| 848 | struct sh_flctl_platform_data *pdata; | 859 | struct sh_flctl_platform_data *pdata; |
| 849 | int ret = -ENXIO; | 860 | int ret = -ENXIO; |
| 861 | int irq; | ||
| 850 | 862 | ||
| 851 | pdata = pdev->dev.platform_data; | 863 | pdata = pdev->dev.platform_data; |
| 852 | if (pdata == NULL) { | 864 | if (pdata == NULL) { |
| @@ -872,14 +884,27 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
| 872 | goto err_iomap; | 884 | goto err_iomap; |
| 873 | } | 885 | } |
| 874 | 886 | ||
| 887 | irq = platform_get_irq(pdev, 0); | ||
| 888 | if (irq < 0) { | ||
| 889 | dev_err(&pdev->dev, "failed to get flste irq data\n"); | ||
| 890 | goto err_flste; | ||
| 891 | } | ||
| 892 | |||
| 893 | ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl); | ||
| 894 | if (ret) { | ||
| 895 | dev_err(&pdev->dev, "request interrupt failed.\n"); | ||
| 896 | goto err_flste; | ||
| 897 | } | ||
| 898 | |||
| 875 | platform_set_drvdata(pdev, flctl); | 899 | platform_set_drvdata(pdev, flctl); |
| 876 | flctl_mtd = &flctl->mtd; | 900 | flctl_mtd = &flctl->mtd; |
| 877 | nand = &flctl->chip; | 901 | nand = &flctl->chip; |
| 878 | flctl_mtd->priv = nand; | 902 | flctl_mtd->priv = nand; |
| 879 | flctl->pdev = pdev; | 903 | flctl->pdev = pdev; |
| 880 | flctl->flcmncr_base = pdata->flcmncr_val; | ||
| 881 | flctl->hwecc = pdata->has_hwecc; | 904 | flctl->hwecc = pdata->has_hwecc; |
| 882 | flctl->holden = pdata->use_holden; | 905 | flctl->holden = pdata->use_holden; |
| 906 | flctl->flcmncr_base = pdata->flcmncr_val; | ||
| 907 | flctl->flintdmacr_base = flctl->hwecc ? (STERINTE | ECERB) : STERINTE; | ||
| 883 | 908 | ||
| 884 | /* Set address of hardware control function */ | 909 | /* Set address of hardware control function */ |
| 885 | /* 20 us command delay time */ | 910 | /* 20 us command delay time */ |
| @@ -918,6 +943,8 @@ static int __devinit flctl_probe(struct platform_device *pdev) | |||
| 918 | 943 | ||
| 919 | err_chip: | 944 | err_chip: |
| 920 | pm_runtime_disable(&pdev->dev); | 945 | pm_runtime_disable(&pdev->dev); |
| 946 | free_irq(irq, flctl); | ||
| 947 | err_flste: | ||
| 921 | iounmap(flctl->reg); | 948 | iounmap(flctl->reg); |
| 922 | err_iomap: | 949 | err_iomap: |
| 923 | kfree(flctl); | 950 | kfree(flctl); |
| @@ -930,6 +957,7 @@ static int __devexit flctl_remove(struct platform_device *pdev) | |||
| 930 | 957 | ||
| 931 | nand_release(&flctl->mtd); | 958 | nand_release(&flctl->mtd); |
| 932 | pm_runtime_disable(&pdev->dev); | 959 | pm_runtime_disable(&pdev->dev); |
| 960 | free_irq(platform_get_irq(pdev, 0), flctl); | ||
| 933 | iounmap(flctl->reg); | 961 | iounmap(flctl->reg); |
| 934 | kfree(flctl); | 962 | kfree(flctl); |
| 935 | 963 | ||
diff --git a/include/linux/mtd/sh_flctl.h b/include/linux/mtd/sh_flctl.h index a38e1fa8af01..2daa43e17039 100644 --- a/include/linux/mtd/sh_flctl.h +++ b/include/linux/mtd/sh_flctl.h | |||
| @@ -107,6 +107,14 @@ | |||
| 107 | #define DOCMD2_E (0x1 << 17) /* 2nd cmd stage execute */ | 107 | #define DOCMD2_E (0x1 << 17) /* 2nd cmd stage execute */ |
| 108 | #define DOCMD1_E (0x1 << 16) /* 1st cmd stage execute */ | 108 | #define DOCMD1_E (0x1 << 16) /* 1st cmd stage execute */ |
| 109 | 109 | ||
| 110 | /* FLINTDMACR control bits */ | ||
| 111 | #define ESTERINTE (0x1 << 24) /* ECC error interrupt enable */ | ||
| 112 | #define AC1CLR (0x1 << 19) /* ECC FIFO clear */ | ||
| 113 | #define AC0CLR (0x1 << 18) /* Data FIFO clear */ | ||
| 114 | #define ECERB (0x1 << 9) /* ECC error */ | ||
| 115 | #define STERB (0x1 << 8) /* Status error */ | ||
| 116 | #define STERINTE (0x1 << 4) /* Status error enable */ | ||
| 117 | |||
| 110 | /* FLTRCR control bits */ | 118 | /* FLTRCR control bits */ |
| 111 | #define TRSTRT (0x1 << 0) /* translation start */ | 119 | #define TRSTRT (0x1 << 0) /* translation start */ |
| 112 | #define TREND (0x1 << 1) /* translation end */ | 120 | #define TREND (0x1 << 1) /* translation end */ |
| @@ -145,6 +153,7 @@ struct sh_flctl { | |||
| 145 | uint32_t erase_ADRCNT; /* bits of FLCMDCR in ERASE1 cmd */ | 153 | uint32_t erase_ADRCNT; /* bits of FLCMDCR in ERASE1 cmd */ |
| 146 | uint32_t rw_ADRCNT; /* bits of FLCMDCR in READ WRITE cmd */ | 154 | uint32_t rw_ADRCNT; /* bits of FLCMDCR in READ WRITE cmd */ |
| 147 | uint32_t flcmncr_base; /* base value of FLCMNCR */ | 155 | uint32_t flcmncr_base; /* base value of FLCMNCR */ |
| 156 | uint32_t flintdmacr_base; /* irq enable bits */ | ||
| 148 | 157 | ||
| 149 | int hwecc_cant_correct[4]; | 158 | int hwecc_cant_correct[4]; |
| 150 | 159 | ||
