diff options
author | Jamie Iles <jamie@jamieiles.com> | 2011-12-18 05:00:49 -0500 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2012-01-09 13:23:58 -0500 |
commit | 775c32208708de3e2e2379c85e429ab11957f864 (patch) | |
tree | 1b40ad4ce02cdea3ae988c9ce8fe4e14986ec875 /drivers/mtd/nand | |
parent | f98872fc14ecb96f796443911b6bc4767e58e885 (diff) |
mtd: gpio-nand: add device tree bindings
Add device tree bindings so that the gpio-nand driver may be
instantiated from the device tree. This also allows the partitions
to be specified in the device tree.
v7: - restore runtime device tree/non device tree detection
v6: - convert to mtd_device_parse_register()
v5: - fold dt config helpers into a single gpio_nand_of_get_config()
v4: - get io sync address from gpio-control-nand,io-sync-reg
property rather than a resource
- clarified a few details in the binding
v3: - remove redundant cast and a couple of whitespace/naming
changes
v2: - add CONFIG_OF guards for non-dt platforms
- compatible becomes gpio-control-nand
- clarify some binding details
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/gpio.c | 115 |
1 files changed, 108 insertions, 7 deletions
diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 2c2060b2800e..27000a5f5f47 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include <linux/mtd/nand.h> | 27 | #include <linux/mtd/nand.h> |
28 | #include <linux/mtd/partitions.h> | 28 | #include <linux/mtd/partitions.h> |
29 | #include <linux/mtd/nand-gpio.h> | 29 | #include <linux/mtd/nand-gpio.h> |
30 | #include <linux/of.h> | ||
31 | #include <linux/of_address.h> | ||
32 | #include <linux/of_gpio.h> | ||
30 | 33 | ||
31 | struct gpiomtd { | 34 | struct gpiomtd { |
32 | void __iomem *io_sync; | 35 | void __iomem *io_sync; |
@@ -171,6 +174,96 @@ static int gpio_nand_devready(struct mtd_info *mtd) | |||
171 | return gpio_get_value(gpiomtd->plat.gpio_rdy); | 174 | return gpio_get_value(gpiomtd->plat.gpio_rdy); |
172 | } | 175 | } |
173 | 176 | ||
177 | #ifdef CONFIG_OF | ||
178 | static const struct of_device_id gpio_nand_id_table[] = { | ||
179 | { .compatible = "gpio-control-nand" }, | ||
180 | {} | ||
181 | }; | ||
182 | MODULE_DEVICE_TABLE(of, gpio_nand_id_table); | ||
183 | |||
184 | static int gpio_nand_get_config_of(const struct device *dev, | ||
185 | struct gpio_nand_platdata *plat) | ||
186 | { | ||
187 | u32 val; | ||
188 | |||
189 | if (!of_property_read_u32(dev->of_node, "bank-width", &val)) { | ||
190 | if (val == 2) { | ||
191 | plat->options |= NAND_BUSWIDTH_16; | ||
192 | } else if (val != 1) { | ||
193 | dev_err(dev, "invalid bank-width %u\n", val); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | plat->gpio_rdy = of_get_gpio(dev->of_node, 0); | ||
199 | plat->gpio_nce = of_get_gpio(dev->of_node, 1); | ||
200 | plat->gpio_ale = of_get_gpio(dev->of_node, 2); | ||
201 | plat->gpio_cle = of_get_gpio(dev->of_node, 3); | ||
202 | plat->gpio_nwp = of_get_gpio(dev->of_node, 4); | ||
203 | |||
204 | if (!of_property_read_u32(dev->of_node, "chip-delay", &val)) | ||
205 | plat->chip_delay = val; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev) | ||
211 | { | ||
212 | struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL); | ||
213 | u64 addr; | ||
214 | |||
215 | if (!r || of_property_read_u64(pdev->dev.of_node, | ||
216 | "gpio-control-nand,io-sync-reg", &addr)) | ||
217 | return NULL; | ||
218 | |||
219 | r->start = addr; | ||
220 | r->end = r->start + 0x3; | ||
221 | r->flags = IORESOURCE_MEM; | ||
222 | |||
223 | return r; | ||
224 | } | ||
225 | #else /* CONFIG_OF */ | ||
226 | #define gpio_nand_id_table NULL | ||
227 | static inline int gpio_nand_get_config_of(const struct device *dev, | ||
228 | struct gpio_nand_platdata *plat) | ||
229 | { | ||
230 | return -ENOSYS; | ||
231 | } | ||
232 | |||
233 | static inline struct resource * | ||
234 | gpio_nand_get_io_sync_of(struct platform_device *pdev) | ||
235 | { | ||
236 | return NULL; | ||
237 | } | ||
238 | #endif /* CONFIG_OF */ | ||
239 | |||
240 | static inline int gpio_nand_get_config(const struct device *dev, | ||
241 | struct gpio_nand_platdata *plat) | ||
242 | { | ||
243 | int ret = gpio_nand_get_config_of(dev, plat); | ||
244 | |||
245 | if (!ret) | ||
246 | return ret; | ||
247 | |||
248 | if (dev->platform_data) { | ||
249 | memcpy(plat, dev->platform_data, sizeof(*plat)); | ||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | static inline struct resource * | ||
257 | gpio_nand_get_io_sync(struct platform_device *pdev) | ||
258 | { | ||
259 | struct resource *r = gpio_nand_get_io_sync_of(pdev); | ||
260 | |||
261 | if (r) | ||
262 | return r; | ||
263 | |||
264 | return platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
265 | } | ||
266 | |||
174 | static int __devexit gpio_nand_remove(struct platform_device *dev) | 267 | static int __devexit gpio_nand_remove(struct platform_device *dev) |
175 | { | 268 | { |
176 | struct gpiomtd *gpiomtd = platform_get_drvdata(dev); | 269 | struct gpiomtd *gpiomtd = platform_get_drvdata(dev); |
@@ -178,7 +271,7 @@ static int __devexit gpio_nand_remove(struct platform_device *dev) | |||
178 | 271 | ||
179 | nand_release(&gpiomtd->mtd_info); | 272 | nand_release(&gpiomtd->mtd_info); |
180 | 273 | ||
181 | res = platform_get_resource(dev, IORESOURCE_MEM, 1); | 274 | res = gpio_nand_get_io_sync(dev); |
182 | iounmap(gpiomtd->io_sync); | 275 | iounmap(gpiomtd->io_sync); |
183 | if (res) | 276 | if (res) |
184 | release_mem_region(res->start, resource_size(res)); | 277 | release_mem_region(res->start, resource_size(res)); |
@@ -226,9 +319,10 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) | |||
226 | struct gpiomtd *gpiomtd; | 319 | struct gpiomtd *gpiomtd; |
227 | struct nand_chip *this; | 320 | struct nand_chip *this; |
228 | struct resource *res0, *res1; | 321 | struct resource *res0, *res1; |
229 | int ret; | 322 | struct mtd_part_parser_data ppdata = {}; |
323 | int ret = 0; | ||
230 | 324 | ||
231 | if (!dev->dev.platform_data) | 325 | if (!dev->dev.of_node && !dev->dev.platform_data) |
232 | return -EINVAL; | 326 | return -EINVAL; |
233 | 327 | ||
234 | res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); | 328 | res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); |
@@ -248,7 +342,7 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) | |||
248 | goto err_map; | 342 | goto err_map; |
249 | } | 343 | } |
250 | 344 | ||
251 | res1 = platform_get_resource(dev, IORESOURCE_MEM, 1); | 345 | res1 = gpio_nand_get_io_sync(dev); |
252 | if (res1) { | 346 | if (res1) { |
253 | gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); | 347 | gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); |
254 | if (!gpiomtd->io_sync) { | 348 | if (!gpiomtd->io_sync) { |
@@ -257,7 +351,9 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) | |||
257 | } | 351 | } |
258 | } | 352 | } |
259 | 353 | ||
260 | memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat)); | 354 | ret = gpio_nand_get_config(&dev->dev, &gpiomtd->plat); |
355 | if (ret) | ||
356 | goto err_nce; | ||
261 | 357 | ||
262 | ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); | 358 | ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); |
263 | if (ret) | 359 | if (ret) |
@@ -316,8 +412,12 @@ static int __devinit gpio_nand_probe(struct platform_device *dev) | |||
316 | gpiomtd->plat.adjust_parts(&gpiomtd->plat, | 412 | gpiomtd->plat.adjust_parts(&gpiomtd->plat, |
317 | gpiomtd->mtd_info.size); | 413 | gpiomtd->mtd_info.size); |
318 | 414 | ||
319 | mtd_device_register(&gpiomtd->mtd_info, gpiomtd->plat.parts, | 415 | ppdata.of_node = dev->dev.of_node; |
320 | gpiomtd->plat.num_parts); | 416 | ret = mtd_device_parse_register(&gpiomtd->mtd_info, NULL, &ppdata, |
417 | gpiomtd->plat.parts, | ||
418 | gpiomtd->plat.num_parts); | ||
419 | if (ret) | ||
420 | goto err_wp; | ||
321 | platform_set_drvdata(dev, gpiomtd); | 421 | platform_set_drvdata(dev, gpiomtd); |
322 | 422 | ||
323 | return 0; | 423 | return 0; |
@@ -352,6 +452,7 @@ static struct platform_driver gpio_nand_driver = { | |||
352 | .remove = gpio_nand_remove, | 452 | .remove = gpio_nand_remove, |
353 | .driver = { | 453 | .driver = { |
354 | .name = "gpio-nand", | 454 | .name = "gpio-nand", |
455 | .of_match_table = gpio_nand_id_table, | ||
355 | }, | 456 | }, |
356 | }; | 457 | }; |
357 | 458 | ||