diff options
Diffstat (limited to 'drivers/mtd/nand/fsl_upm.c')
-rw-r--r-- | drivers/mtd/nand/fsl_upm.c | 68 |
1 files changed, 43 insertions, 25 deletions
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c index 1ebfd87f00b..024e3fffd4b 100644 --- a/drivers/mtd/nand/fsl_upm.c +++ b/drivers/mtd/nand/fsl_upm.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/delay.h> | ||
16 | #include <linux/mtd/nand.h> | 17 | #include <linux/mtd/nand.h> |
17 | #include <linux/mtd/nand_ecc.h> | 18 | #include <linux/mtd/nand_ecc.h> |
18 | #include <linux/mtd/partitions.h> | 19 | #include <linux/mtd/partitions.h> |
@@ -36,8 +37,6 @@ struct fsl_upm_nand { | |||
36 | uint8_t upm_cmd_offset; | 37 | uint8_t upm_cmd_offset; |
37 | void __iomem *io_base; | 38 | void __iomem *io_base; |
38 | int rnb_gpio; | 39 | int rnb_gpio; |
39 | const uint32_t *wait_pattern; | ||
40 | const uint32_t *wait_write; | ||
41 | int chip_delay; | 40 | int chip_delay; |
42 | }; | 41 | }; |
43 | 42 | ||
@@ -61,10 +60,11 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun) | |||
61 | if (fun->rnb_gpio >= 0) { | 60 | if (fun->rnb_gpio >= 0) { |
62 | while (--cnt && !fun_chip_ready(&fun->mtd)) | 61 | while (--cnt && !fun_chip_ready(&fun->mtd)) |
63 | cpu_relax(); | 62 | cpu_relax(); |
63 | if (!cnt) | ||
64 | dev_err(fun->dev, "tired waiting for RNB\n"); | ||
65 | } else { | ||
66 | ndelay(100); | ||
64 | } | 67 | } |
65 | |||
66 | if (!cnt) | ||
67 | dev_err(fun->dev, "tired waiting for RNB\n"); | ||
68 | } | 68 | } |
69 | 69 | ||
70 | static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 70 | static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
@@ -89,8 +89,7 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
89 | 89 | ||
90 | fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd); | 90 | fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd); |
91 | 91 | ||
92 | if (fun->wait_pattern) | 92 | fun_wait_rnb(fun); |
93 | fun_wait_rnb(fun); | ||
94 | } | 93 | } |
95 | 94 | ||
96 | static uint8_t fun_read_byte(struct mtd_info *mtd) | 95 | static uint8_t fun_read_byte(struct mtd_info *mtd) |
@@ -116,14 +115,16 @@ static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
116 | 115 | ||
117 | for (i = 0; i < len; i++) { | 116 | for (i = 0; i < len; i++) { |
118 | out_8(fun->chip.IO_ADDR_W, buf[i]); | 117 | out_8(fun->chip.IO_ADDR_W, buf[i]); |
119 | if (fun->wait_write) | 118 | fun_wait_rnb(fun); |
120 | fun_wait_rnb(fun); | ||
121 | } | 119 | } |
122 | } | 120 | } |
123 | 121 | ||
124 | static int __devinit fun_chip_init(struct fsl_upm_nand *fun) | 122 | static int __devinit fun_chip_init(struct fsl_upm_nand *fun, |
123 | const struct device_node *upm_np, | ||
124 | const struct resource *io_res) | ||
125 | { | 125 | { |
126 | int ret; | 126 | int ret; |
127 | struct device_node *flash_np; | ||
127 | #ifdef CONFIG_MTD_PARTITIONS | 128 | #ifdef CONFIG_MTD_PARTITIONS |
128 | static const char *part_types[] = { "cmdlinepart", NULL, }; | 129 | static const char *part_types[] = { "cmdlinepart", NULL, }; |
129 | #endif | 130 | #endif |
@@ -143,18 +144,37 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun) | |||
143 | fun->mtd.priv = &fun->chip; | 144 | fun->mtd.priv = &fun->chip; |
144 | fun->mtd.owner = THIS_MODULE; | 145 | fun->mtd.owner = THIS_MODULE; |
145 | 146 | ||
147 | flash_np = of_get_next_child(upm_np, NULL); | ||
148 | if (!flash_np) | ||
149 | return -ENODEV; | ||
150 | |||
151 | fun->mtd.name = kasprintf(GFP_KERNEL, "%x.%s", io_res->start, | ||
152 | flash_np->name); | ||
153 | if (!fun->mtd.name) { | ||
154 | ret = -ENOMEM; | ||
155 | goto err; | ||
156 | } | ||
157 | |||
146 | ret = nand_scan(&fun->mtd, 1); | 158 | ret = nand_scan(&fun->mtd, 1); |
147 | if (ret) | 159 | if (ret) |
148 | return ret; | 160 | goto err; |
149 | |||
150 | fun->mtd.name = fun->dev->bus_id; | ||
151 | 161 | ||
152 | #ifdef CONFIG_MTD_PARTITIONS | 162 | #ifdef CONFIG_MTD_PARTITIONS |
153 | ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); | 163 | ret = parse_mtd_partitions(&fun->mtd, part_types, &fun->parts, 0); |
164 | |||
165 | #ifdef CONFIG_MTD_OF_PARTS | ||
166 | if (ret == 0) | ||
167 | ret = of_mtd_parse_partitions(fun->dev, &fun->mtd, | ||
168 | flash_np, &fun->parts); | ||
169 | #endif | ||
154 | if (ret > 0) | 170 | if (ret > 0) |
155 | return add_mtd_partitions(&fun->mtd, fun->parts, ret); | 171 | ret = add_mtd_partitions(&fun->mtd, fun->parts, ret); |
172 | else | ||
156 | #endif | 173 | #endif |
157 | return add_mtd_device(&fun->mtd); | 174 | ret = add_mtd_device(&fun->mtd); |
175 | err: | ||
176 | of_node_put(flash_np); | ||
177 | return ret; | ||
158 | } | 178 | } |
159 | 179 | ||
160 | static int __devinit fun_probe(struct of_device *ofdev, | 180 | static int __devinit fun_probe(struct of_device *ofdev, |
@@ -211,6 +231,12 @@ static int __devinit fun_probe(struct of_device *ofdev, | |||
211 | goto err2; | 231 | goto err2; |
212 | } | 232 | } |
213 | 233 | ||
234 | prop = of_get_property(ofdev->node, "chip-delay", NULL); | ||
235 | if (prop) | ||
236 | fun->chip_delay = *prop; | ||
237 | else | ||
238 | fun->chip_delay = 50; | ||
239 | |||
214 | fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, | 240 | fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, |
215 | io_res.end - io_res.start + 1); | 241 | io_res.end - io_res.start + 1); |
216 | if (!fun->io_base) { | 242 | if (!fun->io_base) { |
@@ -220,17 +246,8 @@ static int __devinit fun_probe(struct of_device *ofdev, | |||
220 | 246 | ||
221 | fun->dev = &ofdev->dev; | 247 | fun->dev = &ofdev->dev; |
222 | fun->last_ctrl = NAND_CLE; | 248 | fun->last_ctrl = NAND_CLE; |
223 | fun->wait_pattern = of_get_property(ofdev->node, "fsl,wait-pattern", | ||
224 | NULL); | ||
225 | fun->wait_write = of_get_property(ofdev->node, "fsl,wait-write", NULL); | ||
226 | |||
227 | prop = of_get_property(ofdev->node, "chip-delay", NULL); | ||
228 | if (prop) | ||
229 | fun->chip_delay = *prop; | ||
230 | else | ||
231 | fun->chip_delay = 50; | ||
232 | 249 | ||
233 | ret = fun_chip_init(fun); | 250 | ret = fun_chip_init(fun, ofdev->node, &io_res); |
234 | if (ret) | 251 | if (ret) |
235 | goto err2; | 252 | goto err2; |
236 | 253 | ||
@@ -251,6 +268,7 @@ static int __devexit fun_remove(struct of_device *ofdev) | |||
251 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); | 268 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); |
252 | 269 | ||
253 | nand_release(&fun->mtd); | 270 | nand_release(&fun->mtd); |
271 | kfree(fun->mtd.name); | ||
254 | 272 | ||
255 | if (fun->rnb_gpio >= 0) | 273 | if (fun->rnb_gpio >= 0) |
256 | gpio_free(fun->rnb_gpio); | 274 | gpio_free(fun->rnb_gpio); |