Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
plat_nand.c
Go to the documentation of this file.
1 /*
2  * Generic NAND driver
3  *
4  * Author: Vitaly Wool <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  */
11 
12 #include <linux/io.h>
13 #include <linux/module.h>
14 #include <linux/platform_device.h>
15 #include <linux/slab.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/nand.h>
18 #include <linux/mtd/partitions.h>
19 
21  struct nand_chip chip;
22  struct mtd_info mtd;
24 };
25 
26 static const char *part_probe_types[] = { "cmdlinepart", NULL };
27 
28 /*
29  * Probe for the NAND device.
30  */
31 static int __devinit plat_nand_probe(struct platform_device *pdev)
32 {
33  struct platform_nand_data *pdata = pdev->dev.platform_data;
35  struct plat_nand_data *data;
36  struct resource *res;
37  const char **part_types;
38  int err = 0;
39 
40  if (!pdata) {
41  dev_err(&pdev->dev, "platform_nand_data is missing\n");
42  return -EINVAL;
43  }
44 
45  if (pdata->chip.nr_chips < 1) {
46  dev_err(&pdev->dev, "invalid number of chips specified\n");
47  return -EINVAL;
48  }
49 
50  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
51  if (!res)
52  return -ENXIO;
53 
54  /* Allocate memory for the device structure (and zero it) */
55  data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
56  if (!data) {
57  dev_err(&pdev->dev, "failed to allocate device structure.\n");
58  return -ENOMEM;
59  }
60 
61  if (!request_mem_region(res->start, resource_size(res),
62  dev_name(&pdev->dev))) {
63  dev_err(&pdev->dev, "request_mem_region failed\n");
64  err = -EBUSY;
65  goto out_free;
66  }
67 
68  data->io_base = ioremap(res->start, resource_size(res));
69  if (data->io_base == NULL) {
70  dev_err(&pdev->dev, "ioremap failed\n");
71  err = -EIO;
72  goto out_release_io;
73  }
74 
75  data->chip.priv = &data;
76  data->mtd.priv = &data->chip;
77  data->mtd.owner = THIS_MODULE;
78  data->mtd.name = dev_name(&pdev->dev);
79 
80  data->chip.IO_ADDR_R = data->io_base;
81  data->chip.IO_ADDR_W = data->io_base;
82  data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
83  data->chip.dev_ready = pdata->ctrl.dev_ready;
84  data->chip.select_chip = pdata->ctrl.select_chip;
85  data->chip.write_buf = pdata->ctrl.write_buf;
86  data->chip.read_buf = pdata->ctrl.read_buf;
87  data->chip.read_byte = pdata->ctrl.read_byte;
88  data->chip.chip_delay = pdata->chip.chip_delay;
89  data->chip.options |= pdata->chip.options;
90  data->chip.bbt_options |= pdata->chip.bbt_options;
91 
92  data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
93  data->chip.ecc.layout = pdata->chip.ecclayout;
94  data->chip.ecc.mode = NAND_ECC_SOFT;
95 
96  platform_set_drvdata(pdev, data);
97 
98  /* Handle any platform specific setup */
99  if (pdata->ctrl.probe) {
100  err = pdata->ctrl.probe(pdev);
101  if (err)
102  goto out;
103  }
104 
105  /* Scan to find existence of the device */
106  if (nand_scan(&data->mtd, pdata->chip.nr_chips)) {
107  err = -ENXIO;
108  goto out;
109  }
110 
111  part_types = pdata->chip.part_probe_types ? : part_probe_types;
112 
113  ppdata.of_node = pdev->dev.of_node;
114  err = mtd_device_parse_register(&data->mtd, part_types, &ppdata,
115  pdata->chip.partitions,
116  pdata->chip.nr_partitions);
117 
118  if (!err)
119  return err;
120 
121  nand_release(&data->mtd);
122 out:
123  if (pdata->ctrl.remove)
124  pdata->ctrl.remove(pdev);
125  platform_set_drvdata(pdev, NULL);
126  iounmap(data->io_base);
127 out_release_io:
128  release_mem_region(res->start, resource_size(res));
129 out_free:
130  kfree(data);
131  return err;
132 }
133 
134 /*
135  * Remove a NAND device.
136  */
137 static int __devexit plat_nand_remove(struct platform_device *pdev)
138 {
139  struct plat_nand_data *data = platform_get_drvdata(pdev);
140  struct platform_nand_data *pdata = pdev->dev.platform_data;
141  struct resource *res;
142 
143  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
144 
145  nand_release(&data->mtd);
146  if (pdata->ctrl.remove)
147  pdata->ctrl.remove(pdev);
148  iounmap(data->io_base);
149  release_mem_region(res->start, resource_size(res));
150  kfree(data);
151 
152  return 0;
153 }
154 
155 static const struct of_device_id plat_nand_match[] = {
156  { .compatible = "gen_nand" },
157  {},
158 };
159 MODULE_DEVICE_TABLE(of, plat_nand_match);
160 
161 static struct platform_driver plat_nand_driver = {
162  .probe = plat_nand_probe,
163  .remove = __devexit_p(plat_nand_remove),
164  .driver = {
165  .name = "gen_nand",
166  .owner = THIS_MODULE,
167  .of_match_table = plat_nand_match,
168  },
169 };
170 
171 module_platform_driver(plat_nand_driver);
172 
173 MODULE_LICENSE("GPL");
174 MODULE_AUTHOR("Vitaly Wool");
175 MODULE_DESCRIPTION("Simple generic NAND driver");
176 MODULE_ALIAS("platform:gen_nand");