aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJamie Iles <jamie@jamieiles.com>2011-12-18 05:00:49 -0500
committerDavid Woodhouse <David.Woodhouse@intel.com>2012-01-09 13:23:58 -0500
commit775c32208708de3e2e2379c85e429ab11957f864 (patch)
tree1b40ad4ce02cdea3ae988c9ce8fe4e14986ec875
parentf98872fc14ecb96f796443911b6bc4767e58e885 (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>
-rw-r--r--Documentation/devicetree/bindings/mtd/gpio-control-nand.txt44
-rw-r--r--drivers/mtd/nand/gpio.c115
2 files changed, 152 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt
new file mode 100644
index 000000000000..719f4dc58df7
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/gpio-control-nand.txt
@@ -0,0 +1,44 @@
1GPIO assisted NAND flash
2
3The GPIO assisted NAND flash uses a memory mapped interface to
4read/write the NAND commands and data and GPIO pins for the control
5signals.
6
7Required properties:
8- compatible : "gpio-control-nand"
9- reg : should specify localbus chip select and size used for the chip. The
10 resource describes the data bus connected to the NAND flash and all accesses
11 are made in native endianness.
12- #address-cells, #size-cells : Must be present if the device has sub-nodes
13 representing partitions.
14- gpios : specifies the gpio pins to control the NAND device. nwp is an
15 optional gpio and may be set to 0 if not present.
16
17Optional properties:
18- bank-width : Width (in bytes) of the device. If not present, the width
19 defaults to 1 byte.
20- chip-delay : chip dependent delay for transferring data from array to
21 read registers (tR). If not present then a default of 20us is used.
22- gpio-control-nand,io-sync-reg : A 64-bit physical address for a read
23 location used to guard against bus reordering with regards to accesses to
24 the GPIO's and the NAND flash data bus. If present, then after changing
25 GPIO state and before and after command byte writes, this register will be
26 read to ensure that the GPIO accesses have completed.
27
28Examples:
29
30gpio-nand@1,0 {
31 compatible = "gpio-control-nand";
32 reg = <1 0x0000 0x2>;
33 #address-cells = <1>;
34 #size-cells = <1>;
35 gpios = <&banka 1 0 /* rdy */
36 &banka 2 0 /* nce */
37 &banka 3 0 /* ale */
38 &banka 4 0 /* cle */
39 0 /* nwp */>;
40
41 partition@0 {
42 ...
43 };
44};
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
31struct gpiomtd { 34struct 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
178static const struct of_device_id gpio_nand_id_table[] = {
179 { .compatible = "gpio-control-nand" },
180 {}
181};
182MODULE_DEVICE_TABLE(of, gpio_nand_id_table);
183
184static 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
210static 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
227static inline int gpio_nand_get_config_of(const struct device *dev,
228 struct gpio_nand_platdata *plat)
229{
230 return -ENOSYS;
231}
232
233static inline struct resource *
234gpio_nand_get_io_sync_of(struct platform_device *pdev)
235{
236 return NULL;
237}
238#endif /* CONFIG_OF */
239
240static 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
256static inline struct resource *
257gpio_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
174static int __devexit gpio_nand_remove(struct platform_device *dev) 267static 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