diff options
-rw-r--r-- | Documentation/powerpc/dts-bindings/4xx/ndfc.txt | 39 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 269 |
3 files changed, 179 insertions, 136 deletions
diff --git a/Documentation/powerpc/dts-bindings/4xx/ndfc.txt b/Documentation/powerpc/dts-bindings/4xx/ndfc.txt new file mode 100644 index 000000000000..869f0b5f16e8 --- /dev/null +++ b/Documentation/powerpc/dts-bindings/4xx/ndfc.txt | |||
@@ -0,0 +1,39 @@ | |||
1 | AMCC NDFC (NanD Flash Controller) | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "ibm,ndfc". | ||
5 | - reg : should specify chip select and size used for the chip (0x2000). | ||
6 | |||
7 | Optional properties: | ||
8 | - ccr : NDFC config and control register value (default 0). | ||
9 | - bank-settings : NDFC bank configuration register value (default 0). | ||
10 | |||
11 | Notes: | ||
12 | - partition(s) - follows the OF MTD standard for partitions | ||
13 | |||
14 | Example: | ||
15 | |||
16 | ndfc@1,0 { | ||
17 | compatible = "ibm,ndfc"; | ||
18 | reg = <0x00000001 0x00000000 0x00002000>; | ||
19 | ccr = <0x00001000>; | ||
20 | bank-settings = <0x80002222>; | ||
21 | #address-cells = <1>; | ||
22 | #size-cells = <1>; | ||
23 | |||
24 | nand { | ||
25 | #address-cells = <1>; | ||
26 | #size-cells = <1>; | ||
27 | |||
28 | partition@0 { | ||
29 | label = "kernel"; | ||
30 | reg = <0x00000000 0x00200000>; | ||
31 | }; | ||
32 | partition@200000 { | ||
33 | label = "root"; | ||
34 | reg = <0x00200000 0x03E00000>; | ||
35 | }; | ||
36 | }; | ||
37 | }; | ||
38 | |||
39 | |||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index f8ae0400c49c..8b12e6e109d3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -163,6 +163,13 @@ config MTD_NAND_S3C2410_HWECC | |||
163 | incorrect ECC generation, and if using these, the default of | 163 | incorrect ECC generation, and if using these, the default of |
164 | software ECC is preferable. | 164 | software ECC is preferable. |
165 | 165 | ||
166 | config MTD_NAND_NDFC | ||
167 | tristate "NDFC NanD Flash Controller" | ||
168 | depends on 4xx | ||
169 | select MTD_NAND_ECC_SMC | ||
170 | help | ||
171 | NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs | ||
172 | |||
166 | config MTD_NAND_S3C2410_CLKSTOP | 173 | config MTD_NAND_S3C2410_CLKSTOP |
167 | bool "S3C2410 NAND IDLE clock stop" | 174 | bool "S3C2410 NAND IDLE clock stop" |
168 | depends on MTD_NAND_S3C2410 | 175 | depends on MTD_NAND_S3C2410 |
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 955959eb02d4..582cf80f555a 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -2,12 +2,20 @@ | |||
2 | * drivers/mtd/ndfc.c | 2 | * drivers/mtd/ndfc.c |
3 | * | 3 | * |
4 | * Overview: | 4 | * Overview: |
5 | * Platform independend driver for NDFC (NanD Flash Controller) | 5 | * Platform independent driver for NDFC (NanD Flash Controller) |
6 | * integrated into EP440 cores | 6 | * integrated into EP440 cores |
7 | * | 7 | * |
8 | * Ported to an OF platform driver by Sean MacLennan | ||
9 | * | ||
10 | * The NDFC supports multiple chips, but this driver only supports a | ||
11 | * single chip since I do not have access to any boards with | ||
12 | * multiple chips. | ||
13 | * | ||
8 | * Author: Thomas Gleixner | 14 | * Author: Thomas Gleixner |
9 | * | 15 | * |
10 | * Copyright 2006 IBM | 16 | * Copyright 2006 IBM |
17 | * Copyright 2008 PIKA Technologies | ||
18 | * Sean MacLennan <smaclennan@pikatech.com> | ||
11 | * | 19 | * |
12 | * This program is free software; you can redistribute it and/or modify it | 20 | * This program is free software; you can redistribute it and/or modify it |
13 | * under the terms of the GNU General Public License as published by the | 21 | * under the terms of the GNU General Public License as published by the |
@@ -21,27 +29,20 @@ | |||
21 | #include <linux/mtd/partitions.h> | 29 | #include <linux/mtd/partitions.h> |
22 | #include <linux/mtd/ndfc.h> | 30 | #include <linux/mtd/ndfc.h> |
23 | #include <linux/mtd/mtd.h> | 31 | #include <linux/mtd/mtd.h> |
24 | #include <linux/platform_device.h> | 32 | #include <linux/of_platform.h> |
25 | |||
26 | #include <asm/io.h> | 33 | #include <asm/io.h> |
27 | #ifdef CONFIG_40x | ||
28 | #include <asm/ibm405.h> | ||
29 | #else | ||
30 | #include <asm/ibm44x.h> | ||
31 | #endif | ||
32 | |||
33 | struct ndfc_nand_mtd { | ||
34 | struct mtd_info mtd; | ||
35 | struct nand_chip chip; | ||
36 | struct platform_nand_chip *pl_chip; | ||
37 | }; | ||
38 | 34 | ||
39 | static struct ndfc_nand_mtd ndfc_mtd[NDFC_MAX_BANKS]; | ||
40 | 35 | ||
41 | struct ndfc_controller { | 36 | struct ndfc_controller { |
42 | void __iomem *ndfcbase; | 37 | struct of_device *ofdev; |
43 | struct nand_hw_control ndfc_control; | 38 | void __iomem *ndfcbase; |
44 | atomic_t childs_active; | 39 | struct mtd_info mtd; |
40 | struct nand_chip chip; | ||
41 | int chip_select; | ||
42 | struct nand_hw_control ndfc_control; | ||
43 | #ifdef CONFIG_MTD_PARTITIONS | ||
44 | struct mtd_partition *parts; | ||
45 | #endif | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | static struct ndfc_controller ndfc_ctrl; | 48 | static struct ndfc_controller ndfc_ctrl; |
@@ -50,17 +51,14 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) | |||
50 | { | 51 | { |
51 | uint32_t ccr; | 52 | uint32_t ccr; |
52 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 53 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
53 | struct nand_chip *nandchip = mtd->priv; | ||
54 | struct ndfc_nand_mtd *nandmtd = nandchip->priv; | ||
55 | struct platform_nand_chip *pchip = nandmtd->pl_chip; | ||
56 | 54 | ||
57 | ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); | 55 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); |
58 | if (chip >= 0) { | 56 | if (chip >= 0) { |
59 | ccr &= ~NDFC_CCR_BS_MASK; | 57 | ccr &= ~NDFC_CCR_BS_MASK; |
60 | ccr |= NDFC_CCR_BS(chip + pchip->chip_offset); | 58 | ccr |= NDFC_CCR_BS(chip + ndfc->chip_select); |
61 | } else | 59 | } else |
62 | ccr |= NDFC_CCR_RESET_CE; | 60 | ccr |= NDFC_CCR_RESET_CE; |
63 | __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); | 61 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); |
64 | } | 62 | } |
65 | 63 | ||
66 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 64 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
@@ -80,7 +78,7 @@ static int ndfc_ready(struct mtd_info *mtd) | |||
80 | { | 78 | { |
81 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 79 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
82 | 80 | ||
83 | return __raw_readl(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; | 81 | return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; |
84 | } | 82 | } |
85 | 83 | ||
86 | static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) | 84 | static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) |
@@ -88,9 +86,9 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) | |||
88 | uint32_t ccr; | 86 | uint32_t ccr; |
89 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 87 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
90 | 88 | ||
91 | ccr = __raw_readl(ndfc->ndfcbase + NDFC_CCR); | 89 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); |
92 | ccr |= NDFC_CCR_RESET_ECC; | 90 | ccr |= NDFC_CCR_RESET_ECC; |
93 | __raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR); | 91 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); |
94 | wmb(); | 92 | wmb(); |
95 | } | 93 | } |
96 | 94 | ||
@@ -102,9 +100,10 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd, | |||
102 | uint8_t *p = (uint8_t *)&ecc; | 100 | uint8_t *p = (uint8_t *)&ecc; |
103 | 101 | ||
104 | wmb(); | 102 | wmb(); |
105 | ecc = __raw_readl(ndfc->ndfcbase + NDFC_ECC); | 103 | ecc = in_be32(ndfc->ndfcbase + NDFC_ECC); |
106 | ecc_code[0] = p[1]; | 104 | /* The NDFC uses Smart Media (SMC) bytes order */ |
107 | ecc_code[1] = p[2]; | 105 | ecc_code[0] = p[2]; |
106 | ecc_code[1] = p[1]; | ||
108 | ecc_code[2] = p[3]; | 107 | ecc_code[2] = p[3]; |
109 | 108 | ||
110 | return 0; | 109 | return 0; |
@@ -123,7 +122,7 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | |||
123 | uint32_t *p = (uint32_t *) buf; | 122 | uint32_t *p = (uint32_t *) buf; |
124 | 123 | ||
125 | for(;len > 0; len -= 4) | 124 | for(;len > 0; len -= 4) |
126 | *p++ = __raw_readl(ndfc->ndfcbase + NDFC_DATA); | 125 | *p++ = in_be32(ndfc->ndfcbase + NDFC_DATA); |
127 | } | 126 | } |
128 | 127 | ||
129 | static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 128 | static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
@@ -132,7 +131,7 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
132 | uint32_t *p = (uint32_t *) buf; | 131 | uint32_t *p = (uint32_t *) buf; |
133 | 132 | ||
134 | for(;len > 0; len -= 4) | 133 | for(;len > 0; len -= 4) |
135 | __raw_writel(*p++, ndfc->ndfcbase + NDFC_DATA); | 134 | out_be32(ndfc->ndfcbase + NDFC_DATA, *p++); |
136 | } | 135 | } |
137 | 136 | ||
138 | static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 137 | static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
@@ -141,7 +140,7 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
141 | uint32_t *p = (uint32_t *) buf; | 140 | uint32_t *p = (uint32_t *) buf; |
142 | 141 | ||
143 | for(;len > 0; len -= 4) | 142 | for(;len > 0; len -= 4) |
144 | if (*p++ != __raw_readl(ndfc->ndfcbase + NDFC_DATA)) | 143 | if (*p++ != in_be32(ndfc->ndfcbase + NDFC_DATA)) |
145 | return -EFAULT; | 144 | return -EFAULT; |
146 | return 0; | 145 | return 0; |
147 | } | 146 | } |
@@ -149,10 +148,19 @@ static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
149 | /* | 148 | /* |
150 | * Initialize chip structure | 149 | * Initialize chip structure |
151 | */ | 150 | */ |
152 | static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) | 151 | static int ndfc_chip_init(struct ndfc_controller *ndfc, |
152 | struct device_node *node) | ||
153 | { | 153 | { |
154 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 154 | #ifdef CONFIG_MTD_PARTITIONS |
155 | struct nand_chip *chip = &mtd->chip; | 155 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
156 | static const char *part_types[] = { "cmdlinepart", NULL }; | ||
157 | #else | ||
158 | static const char *part_types[] = { NULL }; | ||
159 | #endif | ||
160 | #endif | ||
161 | struct device_node *flash_np; | ||
162 | struct nand_chip *chip = &ndfc->chip; | ||
163 | int ret; | ||
156 | 164 | ||
157 | chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; | 165 | chip->IO_ADDR_R = ndfc->ndfcbase + NDFC_DATA; |
158 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; | 166 | chip->IO_ADDR_W = ndfc->ndfcbase + NDFC_DATA; |
@@ -160,8 +168,6 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) | |||
160 | chip->dev_ready = ndfc_ready; | 168 | chip->dev_ready = ndfc_ready; |
161 | chip->select_chip = ndfc_select_chip; | 169 | chip->select_chip = ndfc_select_chip; |
162 | chip->chip_delay = 50; | 170 | chip->chip_delay = 50; |
163 | chip->priv = mtd; | ||
164 | chip->options = mtd->pl_chip->options; | ||
165 | chip->controller = &ndfc->ndfc_control; | 171 | chip->controller = &ndfc->ndfc_control; |
166 | chip->read_buf = ndfc_read_buf; | 172 | chip->read_buf = ndfc_read_buf; |
167 | chip->write_buf = ndfc_write_buf; | 173 | chip->write_buf = ndfc_write_buf; |
@@ -172,143 +178,136 @@ static void ndfc_chip_init(struct ndfc_nand_mtd *mtd) | |||
172 | chip->ecc.mode = NAND_ECC_HW; | 178 | chip->ecc.mode = NAND_ECC_HW; |
173 | chip->ecc.size = 256; | 179 | chip->ecc.size = 256; |
174 | chip->ecc.bytes = 3; | 180 | chip->ecc.bytes = 3; |
175 | chip->ecclayout = chip->ecc.layout = mtd->pl_chip->ecclayout; | ||
176 | mtd->mtd.priv = chip; | ||
177 | mtd->mtd.owner = THIS_MODULE; | ||
178 | } | ||
179 | |||
180 | static int ndfc_chip_probe(struct platform_device *pdev) | ||
181 | { | ||
182 | struct platform_nand_chip *nc = pdev->dev.platform_data; | ||
183 | struct ndfc_chip_settings *settings = nc->priv; | ||
184 | struct ndfc_controller *ndfc = &ndfc_ctrl; | ||
185 | struct ndfc_nand_mtd *nandmtd; | ||
186 | |||
187 | if (nc->chip_offset >= NDFC_MAX_BANKS || nc->nr_chips > NDFC_MAX_BANKS) | ||
188 | return -EINVAL; | ||
189 | |||
190 | /* Set the bank settings */ | ||
191 | __raw_writel(settings->bank_settings, | ||
192 | ndfc->ndfcbase + NDFC_BCFG0 + (nc->chip_offset << 2)); | ||
193 | 181 | ||
194 | nandmtd = &ndfc_mtd[pdev->id]; | 182 | ndfc->mtd.priv = chip; |
195 | if (nandmtd->pl_chip) | 183 | ndfc->mtd.owner = THIS_MODULE; |
196 | return -EBUSY; | ||
197 | 184 | ||
198 | nandmtd->pl_chip = nc; | 185 | flash_np = of_get_next_child(node, NULL); |
199 | ndfc_chip_init(nandmtd); | 186 | if (!flash_np) |
200 | |||
201 | /* Scan for chips */ | ||
202 | if (nand_scan(&nandmtd->mtd, nc->nr_chips)) { | ||
203 | nandmtd->pl_chip = NULL; | ||
204 | return -ENODEV; | 187 | return -ENODEV; |
188 | |||
189 | ndfc->mtd.name = kasprintf(GFP_KERNEL, "%s.%s", | ||
190 | ndfc->ofdev->dev.bus_id, flash_np->name); | ||
191 | if (!ndfc->mtd.name) { | ||
192 | ret = -ENOMEM; | ||
193 | goto err; | ||
205 | } | 194 | } |
206 | 195 | ||
207 | #ifdef CONFIG_MTD_PARTITIONS | 196 | ret = nand_scan(&ndfc->mtd, 1); |
208 | printk("Number of partitions %d\n", nc->nr_partitions); | 197 | if (ret) |
209 | if (nc->nr_partitions) { | 198 | goto err; |
210 | /* Add the full device, so complete dumps can be made */ | ||
211 | add_mtd_device(&nandmtd->mtd); | ||
212 | add_mtd_partitions(&nandmtd->mtd, nc->partitions, | ||
213 | nc->nr_partitions); | ||
214 | 199 | ||
215 | } else | 200 | #ifdef CONFIG_MTD_PARTITIONS |
216 | #else | 201 | ret = parse_mtd_partitions(&ndfc->mtd, part_types, &ndfc->parts, 0); |
217 | add_mtd_device(&nandmtd->mtd); | 202 | if (ret < 0) |
203 | goto err; | ||
204 | |||
205 | #ifdef CONFIG_MTD_OF_PARTS | ||
206 | if (ret == 0) { | ||
207 | ret = of_mtd_parse_partitions(&ndfc->ofdev->dev, flash_np, | ||
208 | &ndfc->parts); | ||
209 | if (ret < 0) | ||
210 | goto err; | ||
211 | } | ||
218 | #endif | 212 | #endif |
219 | 213 | ||
220 | atomic_inc(&ndfc->childs_active); | 214 | if (ret > 0) |
221 | return 0; | 215 | ret = add_mtd_partitions(&ndfc->mtd, ndfc->parts, ret); |
222 | } | 216 | else |
217 | #endif | ||
218 | ret = add_mtd_device(&ndfc->mtd); | ||
223 | 219 | ||
224 | static int ndfc_chip_remove(struct platform_device *pdev) | 220 | err: |
225 | { | 221 | of_node_put(flash_np); |
226 | return 0; | 222 | if (ret) |
223 | kfree(ndfc->mtd.name); | ||
224 | return ret; | ||
227 | } | 225 | } |
228 | 226 | ||
229 | static int ndfc_nand_probe(struct platform_device *pdev) | 227 | static int __devinit ndfc_probe(struct of_device *ofdev, |
228 | const struct of_device_id *match) | ||
230 | { | 229 | { |
231 | struct platform_nand_ctrl *nc = pdev->dev.platform_data; | ||
232 | struct ndfc_controller_settings *settings = nc->priv; | ||
233 | struct resource *res = pdev->resource; | ||
234 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 230 | struct ndfc_controller *ndfc = &ndfc_ctrl; |
235 | unsigned long long phys = settings->ndfc_erpn | res->start; | 231 | const u32 *reg; |
232 | u32 ccr; | ||
233 | int err, len; | ||
236 | 234 | ||
237 | #ifndef CONFIG_PHYS_64BIT | 235 | spin_lock_init(&ndfc->ndfc_control.lock); |
238 | ndfc->ndfcbase = ioremap((phys_addr_t)phys, res->end - res->start + 1); | 236 | init_waitqueue_head(&ndfc->ndfc_control.wq); |
239 | #else | 237 | ndfc->ofdev = ofdev; |
240 | ndfc->ndfcbase = ioremap64(phys, res->end - res->start + 1); | 238 | dev_set_drvdata(&ofdev->dev, ndfc); |
241 | #endif | 239 | |
240 | /* Read the reg property to get the chip select */ | ||
241 | reg = of_get_property(ofdev->node, "reg", &len); | ||
242 | if (reg == NULL || len != 12) { | ||
243 | dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); | ||
244 | return -ENOENT; | ||
245 | } | ||
246 | ndfc->chip_select = reg[0]; | ||
247 | |||
248 | ndfc->ndfcbase = of_iomap(ofdev->node, 0); | ||
242 | if (!ndfc->ndfcbase) { | 249 | if (!ndfc->ndfcbase) { |
243 | printk(KERN_ERR "NDFC: ioremap failed\n"); | 250 | dev_err(&ofdev->dev, "failed to get memory\n"); |
244 | return -EIO; | 251 | return -EIO; |
245 | } | 252 | } |
246 | 253 | ||
247 | __raw_writel(settings->ccr_settings, ndfc->ndfcbase + NDFC_CCR); | 254 | ccr = NDFC_CCR_BS(ndfc->chip_select); |
248 | 255 | ||
249 | spin_lock_init(&ndfc->ndfc_control.lock); | 256 | /* It is ok if ccr does not exist - just default to 0 */ |
250 | init_waitqueue_head(&ndfc->ndfc_control.wq); | 257 | reg = of_get_property(ofdev->node, "ccr", NULL); |
258 | if (reg) | ||
259 | ccr |= *reg; | ||
251 | 260 | ||
252 | platform_set_drvdata(pdev, ndfc); | 261 | out_be32(ndfc->ndfcbase + NDFC_CCR, ccr); |
253 | 262 | ||
254 | printk("NDFC NAND Driver initialized. Chip-Rev: 0x%08x\n", | 263 | /* Set the bank settings if given */ |
255 | __raw_readl(ndfc->ndfcbase + NDFC_REVID)); | 264 | reg = of_get_property(ofdev->node, "bank-settings", NULL); |
265 | if (reg) { | ||
266 | int offset = NDFC_BCFG0 + (ndfc->chip_select << 2); | ||
267 | out_be32(ndfc->ndfcbase + offset, *reg); | ||
268 | } | ||
269 | |||
270 | err = ndfc_chip_init(ndfc, ofdev->node); | ||
271 | if (err) { | ||
272 | iounmap(ndfc->ndfcbase); | ||
273 | return err; | ||
274 | } | ||
256 | 275 | ||
257 | return 0; | 276 | return 0; |
258 | } | 277 | } |
259 | 278 | ||
260 | static int ndfc_nand_remove(struct platform_device *pdev) | 279 | static int __devexit ndfc_remove(struct of_device *ofdev) |
261 | { | 280 | { |
262 | struct ndfc_controller *ndfc = platform_get_drvdata(pdev); | 281 | struct ndfc_controller *ndfc = dev_get_drvdata(&ofdev->dev); |
263 | 282 | ||
264 | if (atomic_read(&ndfc->childs_active)) | 283 | nand_release(&ndfc->mtd); |
265 | return -EBUSY; | ||
266 | 284 | ||
267 | if (ndfc) { | ||
268 | platform_set_drvdata(pdev, NULL); | ||
269 | iounmap(ndfc_ctrl.ndfcbase); | ||
270 | ndfc_ctrl.ndfcbase = NULL; | ||
271 | } | ||
272 | return 0; | 285 | return 0; |
273 | } | 286 | } |
274 | 287 | ||
275 | /* driver device registration */ | 288 | static const struct of_device_id ndfc_match[] = { |
276 | 289 | { .compatible = "ibm,ndfc", }, | |
277 | static struct platform_driver ndfc_chip_driver = { | 290 | {} |
278 | .probe = ndfc_chip_probe, | ||
279 | .remove = ndfc_chip_remove, | ||
280 | .driver = { | ||
281 | .name = "ndfc-chip", | ||
282 | .owner = THIS_MODULE, | ||
283 | }, | ||
284 | }; | 291 | }; |
292 | MODULE_DEVICE_TABLE(of, ndfc_match); | ||
285 | 293 | ||
286 | static struct platform_driver ndfc_nand_driver = { | 294 | static struct of_platform_driver ndfc_driver = { |
287 | .probe = ndfc_nand_probe, | 295 | .driver = { |
288 | .remove = ndfc_nand_remove, | 296 | .name = "ndfc", |
289 | .driver = { | ||
290 | .name = "ndfc-nand", | ||
291 | .owner = THIS_MODULE, | ||
292 | }, | 297 | }, |
298 | .match_table = ndfc_match, | ||
299 | .probe = ndfc_probe, | ||
300 | .remove = __devexit_p(ndfc_remove), | ||
293 | }; | 301 | }; |
294 | 302 | ||
295 | static int __init ndfc_nand_init(void) | 303 | static int __init ndfc_nand_init(void) |
296 | { | 304 | { |
297 | int ret; | 305 | return of_register_platform_driver(&ndfc_driver); |
298 | |||
299 | spin_lock_init(&ndfc_ctrl.ndfc_control.lock); | ||
300 | init_waitqueue_head(&ndfc_ctrl.ndfc_control.wq); | ||
301 | |||
302 | ret = platform_driver_register(&ndfc_nand_driver); | ||
303 | if (!ret) | ||
304 | ret = platform_driver_register(&ndfc_chip_driver); | ||
305 | return ret; | ||
306 | } | 306 | } |
307 | 307 | ||
308 | static void __exit ndfc_nand_exit(void) | 308 | static void __exit ndfc_nand_exit(void) |
309 | { | 309 | { |
310 | platform_driver_unregister(&ndfc_chip_driver); | 310 | of_unregister_platform_driver(&ndfc_driver); |
311 | platform_driver_unregister(&ndfc_nand_driver); | ||
312 | } | 311 | } |
313 | 312 | ||
314 | module_init(ndfc_nand_init); | 313 | module_init(ndfc_nand_init); |
@@ -316,6 +315,4 @@ module_exit(ndfc_nand_exit); | |||
316 | 315 | ||
317 | MODULE_LICENSE("GPL"); | 316 | MODULE_LICENSE("GPL"); |
318 | MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); | 317 | MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); |
319 | MODULE_DESCRIPTION("Platform driver for NDFC"); | 318 | MODULE_DESCRIPTION("OF Platform driver for NDFC"); |
320 | MODULE_ALIAS("platform:ndfc-chip"); | ||
321 | MODULE_ALIAS("platform:ndfc-nand"); | ||