diff options
Diffstat (limited to 'drivers/mtd/nand/s3c2410.c')
-rw-r--r-- | drivers/mtd/nand/s3c2410.c | 75 |
1 files changed, 45 insertions, 30 deletions
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 33d832dddfdd..4405468f196b 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c | |||
@@ -55,7 +55,7 @@ static int hardware_ecc = 0; | |||
55 | #endif | 55 | #endif |
56 | 56 | ||
57 | #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP | 57 | #ifdef CONFIG_MTD_NAND_S3C2410_CLKSTOP |
58 | static int clock_stop = 1; | 58 | static const int clock_stop = 1; |
59 | #else | 59 | #else |
60 | static const int clock_stop = 0; | 60 | static const int clock_stop = 0; |
61 | #endif | 61 | #endif |
@@ -96,6 +96,12 @@ enum s3c_cpu_type { | |||
96 | TYPE_S3C2440, | 96 | TYPE_S3C2440, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | enum s3c_nand_clk_state { | ||
100 | CLOCK_DISABLE = 0, | ||
101 | CLOCK_ENABLE, | ||
102 | CLOCK_SUSPEND, | ||
103 | }; | ||
104 | |||
99 | /* overview of the s3c2410 nand state */ | 105 | /* overview of the s3c2410 nand state */ |
100 | 106 | ||
101 | /** | 107 | /** |
@@ -111,6 +117,7 @@ enum s3c_cpu_type { | |||
111 | * @mtd_count: The number of MTDs created from this controller. | 117 | * @mtd_count: The number of MTDs created from this controller. |
112 | * @save_sel: The contents of @sel_reg to be saved over suspend. | 118 | * @save_sel: The contents of @sel_reg to be saved over suspend. |
113 | * @clk_rate: The clock rate from @clk. | 119 | * @clk_rate: The clock rate from @clk. |
120 | * @clk_state: The current clock state. | ||
114 | * @cpu_type: The exact type of this controller. | 121 | * @cpu_type: The exact type of this controller. |
115 | */ | 122 | */ |
116 | struct s3c2410_nand_info { | 123 | struct s3c2410_nand_info { |
@@ -129,6 +136,7 @@ struct s3c2410_nand_info { | |||
129 | int mtd_count; | 136 | int mtd_count; |
130 | unsigned long save_sel; | 137 | unsigned long save_sel; |
131 | unsigned long clk_rate; | 138 | unsigned long clk_rate; |
139 | enum s3c_nand_clk_state clk_state; | ||
132 | 140 | ||
133 | enum s3c_cpu_type cpu_type; | 141 | enum s3c_cpu_type cpu_type; |
134 | 142 | ||
@@ -159,11 +167,33 @@ static struct s3c2410_platform_nand *to_nand_plat(struct platform_device *dev) | |||
159 | return dev->dev.platform_data; | 167 | return dev->dev.platform_data; |
160 | } | 168 | } |
161 | 169 | ||
162 | static inline int allow_clk_stop(struct s3c2410_nand_info *info) | 170 | static inline int allow_clk_suspend(struct s3c2410_nand_info *info) |
163 | { | 171 | { |
164 | return clock_stop; | 172 | return clock_stop; |
165 | } | 173 | } |
166 | 174 | ||
175 | /** | ||
176 | * s3c2410_nand_clk_set_state - Enable, disable or suspend NAND clock. | ||
177 | * @info: The controller instance. | ||
178 | * @new_state: State to which clock should be set. | ||
179 | */ | ||
180 | static void s3c2410_nand_clk_set_state(struct s3c2410_nand_info *info, | ||
181 | enum s3c_nand_clk_state new_state) | ||
182 | { | ||
183 | if (!allow_clk_suspend(info) && new_state == CLOCK_SUSPEND) | ||
184 | return; | ||
185 | |||
186 | if (info->clk_state == CLOCK_ENABLE) { | ||
187 | if (new_state != CLOCK_ENABLE) | ||
188 | clk_disable(info->clk); | ||
189 | } else { | ||
190 | if (new_state == CLOCK_ENABLE) | ||
191 | clk_enable(info->clk); | ||
192 | } | ||
193 | |||
194 | info->clk_state = new_state; | ||
195 | } | ||
196 | |||
167 | /* timing calculations */ | 197 | /* timing calculations */ |
168 | 198 | ||
169 | #define NS_IN_KHZ 1000000 | 199 | #define NS_IN_KHZ 1000000 |
@@ -333,8 +363,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
333 | nmtd = this->priv; | 363 | nmtd = this->priv; |
334 | info = nmtd->info; | 364 | info = nmtd->info; |
335 | 365 | ||
336 | if (chip != -1 && allow_clk_stop(info)) | 366 | if (chip != -1) |
337 | clk_enable(info->clk); | 367 | s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); |
338 | 368 | ||
339 | cur = readl(info->sel_reg); | 369 | cur = readl(info->sel_reg); |
340 | 370 | ||
@@ -356,8 +386,8 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip) | |||
356 | 386 | ||
357 | writel(cur, info->sel_reg); | 387 | writel(cur, info->sel_reg); |
358 | 388 | ||
359 | if (chip == -1 && allow_clk_stop(info)) | 389 | if (chip == -1) |
360 | clk_disable(info->clk); | 390 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); |
361 | } | 391 | } |
362 | 392 | ||
363 | /* s3c2410_nand_hwcontrol | 393 | /* s3c2410_nand_hwcontrol |
@@ -694,8 +724,7 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) | |||
694 | /* free the common resources */ | 724 | /* free the common resources */ |
695 | 725 | ||
696 | if (info->clk != NULL && !IS_ERR(info->clk)) { | 726 | if (info->clk != NULL && !IS_ERR(info->clk)) { |
697 | if (!allow_clk_stop(info)) | 727 | s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); |
698 | clk_disable(info->clk); | ||
699 | clk_put(info->clk); | 728 | clk_put(info->clk); |
700 | } | 729 | } |
701 | 730 | ||
@@ -715,7 +744,6 @@ static int s3c24xx_nand_remove(struct platform_device *pdev) | |||
715 | return 0; | 744 | return 0; |
716 | } | 745 | } |
717 | 746 | ||
718 | #ifdef CONFIG_MTD_PARTITIONS | ||
719 | const char *part_probes[] = { "cmdlinepart", NULL }; | 747 | const char *part_probes[] = { "cmdlinepart", NULL }; |
720 | static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | 748 | static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, |
721 | struct s3c2410_nand_mtd *mtd, | 749 | struct s3c2410_nand_mtd *mtd, |
@@ -725,7 +753,7 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | |||
725 | int nr_part = 0; | 753 | int nr_part = 0; |
726 | 754 | ||
727 | if (set == NULL) | 755 | if (set == NULL) |
728 | return add_mtd_device(&mtd->mtd); | 756 | return mtd_device_register(&mtd->mtd, NULL, 0); |
729 | 757 | ||
730 | mtd->mtd.name = set->name; | 758 | mtd->mtd.name = set->name; |
731 | nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, &part_info, 0); | 759 | nr_part = parse_mtd_partitions(&mtd->mtd, part_probes, &part_info, 0); |
@@ -735,19 +763,8 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | |||
735 | part_info = set->partitions; | 763 | part_info = set->partitions; |
736 | } | 764 | } |
737 | 765 | ||
738 | if (nr_part > 0 && part_info) | 766 | return mtd_device_register(&mtd->mtd, part_info, nr_part); |
739 | return add_mtd_partitions(&mtd->mtd, part_info, nr_part); | ||
740 | |||
741 | return add_mtd_device(&mtd->mtd); | ||
742 | } | ||
743 | #else | ||
744 | static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, | ||
745 | struct s3c2410_nand_mtd *mtd, | ||
746 | struct s3c2410_nand_set *set) | ||
747 | { | ||
748 | return add_mtd_device(&mtd->mtd); | ||
749 | } | 767 | } |
750 | #endif | ||
751 | 768 | ||
752 | /** | 769 | /** |
753 | * s3c2410_nand_init_chip - initialise a single instance of an chip | 770 | * s3c2410_nand_init_chip - initialise a single instance of an chip |
@@ -947,7 +964,7 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) | |||
947 | goto exit_error; | 964 | goto exit_error; |
948 | } | 965 | } |
949 | 966 | ||
950 | clk_enable(info->clk); | 967 | s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); |
951 | 968 | ||
952 | /* allocate and map the resource */ | 969 | /* allocate and map the resource */ |
953 | 970 | ||
@@ -1026,9 +1043,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) | |||
1026 | goto exit_error; | 1043 | goto exit_error; |
1027 | } | 1044 | } |
1028 | 1045 | ||
1029 | if (allow_clk_stop(info)) { | 1046 | if (allow_clk_suspend(info)) { |
1030 | dev_info(&pdev->dev, "clock idle support enabled\n"); | 1047 | dev_info(&pdev->dev, "clock idle support enabled\n"); |
1031 | clk_disable(info->clk); | 1048 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); |
1032 | } | 1049 | } |
1033 | 1050 | ||
1034 | pr_debug("initialised ok\n"); | 1051 | pr_debug("initialised ok\n"); |
@@ -1059,8 +1076,7 @@ static int s3c24xx_nand_suspend(struct platform_device *dev, pm_message_t pm) | |||
1059 | 1076 | ||
1060 | writel(info->save_sel | info->sel_bit, info->sel_reg); | 1077 | writel(info->save_sel | info->sel_bit, info->sel_reg); |
1061 | 1078 | ||
1062 | if (!allow_clk_stop(info)) | 1079 | s3c2410_nand_clk_set_state(info, CLOCK_DISABLE); |
1063 | clk_disable(info->clk); | ||
1064 | } | 1080 | } |
1065 | 1081 | ||
1066 | return 0; | 1082 | return 0; |
@@ -1072,7 +1088,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
1072 | unsigned long sel; | 1088 | unsigned long sel; |
1073 | 1089 | ||
1074 | if (info) { | 1090 | if (info) { |
1075 | clk_enable(info->clk); | 1091 | s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); |
1076 | s3c2410_nand_inithw(info); | 1092 | s3c2410_nand_inithw(info); |
1077 | 1093 | ||
1078 | /* Restore the state of the nFCE line. */ | 1094 | /* Restore the state of the nFCE line. */ |
@@ -1082,8 +1098,7 @@ static int s3c24xx_nand_resume(struct platform_device *dev) | |||
1082 | sel |= info->save_sel & info->sel_bit; | 1098 | sel |= info->save_sel & info->sel_bit; |
1083 | writel(sel, info->sel_reg); | 1099 | writel(sel, info->sel_reg); |
1084 | 1100 | ||
1085 | if (allow_clk_stop(info)) | 1101 | s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); |
1086 | clk_disable(info->clk); | ||
1087 | } | 1102 | } |
1088 | 1103 | ||
1089 | return 0; | 1104 | return 0; |