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 | ||