1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Updated, and converted to generic GPIO based driver by Russell King. |
4 | * |
5 | * Written by Ben Dooks <ben@simtec.co.uk> |
6 | * Based on 2.4 version by Mark Whittaker |
7 | * |
8 | * © 2004 Simtec Electronics |
9 | * |
10 | * Device driver for NAND flash that uses a memory mapped interface to |
11 | * read/write the NAND commands and data, and GPIO pins for control signals |
12 | * (the DT binding refers to this as "GPIO assisted NAND flash") |
13 | */ |
14 | |
15 | #include <linux/kernel.h> |
16 | #include <linux/err.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/module.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/gpio/consumer.h> |
21 | #include <linux/io.h> |
22 | #include <linux/mtd/mtd.h> |
23 | #include <linux/mtd/rawnand.h> |
24 | #include <linux/mtd/partitions.h> |
25 | #include <linux/mtd/nand-gpio.h> |
26 | #include <linux/of.h> |
27 | #include <linux/of_address.h> |
28 | #include <linux/delay.h> |
29 | |
30 | struct gpiomtd { |
31 | struct nand_controller base; |
32 | void __iomem *io; |
33 | void __iomem *io_sync; |
34 | struct nand_chip nand_chip; |
35 | struct gpio_nand_platdata plat; |
36 | struct gpio_desc *nce; /* Optional chip enable */ |
37 | struct gpio_desc *cle; |
38 | struct gpio_desc *ale; |
39 | struct gpio_desc *rdy; |
40 | struct gpio_desc *nwp; /* Optional write protection */ |
41 | }; |
42 | |
43 | static inline struct gpiomtd *gpio_nand_getpriv(struct mtd_info *mtd) |
44 | { |
45 | return container_of(mtd_to_nand(mtd), struct gpiomtd, nand_chip); |
46 | } |
47 | |
48 | |
49 | #ifdef CONFIG_ARM |
50 | /* gpio_nand_dosync() |
51 | * |
52 | * Make sure the GPIO state changes occur in-order with writes to NAND |
53 | * memory region. |
54 | * Needed on PXA due to bus-reordering within the SoC itself (see section on |
55 | * I/O ordering in PXA manual (section 2.3, p35) |
56 | */ |
57 | static void gpio_nand_dosync(struct gpiomtd *gpiomtd) |
58 | { |
59 | unsigned long tmp; |
60 | |
61 | if (gpiomtd->io_sync) { |
62 | /* |
63 | * Linux memory barriers don't cater for what's required here. |
64 | * What's required is what's here - a read from a separate |
65 | * region with a dependency on that read. |
66 | */ |
67 | tmp = readl(gpiomtd->io_sync); |
68 | asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp)); |
69 | } |
70 | } |
71 | #else |
72 | static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {} |
73 | #endif |
74 | |
75 | static int gpio_nand_exec_instr(struct nand_chip *chip, |
76 | const struct nand_op_instr *instr) |
77 | { |
78 | struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd: nand_to_mtd(chip)); |
79 | unsigned int i; |
80 | |
81 | switch (instr->type) { |
82 | case NAND_OP_CMD_INSTR: |
83 | gpio_nand_dosync(gpiomtd); |
84 | gpiod_set_value(desc: gpiomtd->cle, value: 1); |
85 | gpio_nand_dosync(gpiomtd); |
86 | writeb(val: instr->ctx.cmd.opcode, addr: gpiomtd->io); |
87 | gpio_nand_dosync(gpiomtd); |
88 | gpiod_set_value(desc: gpiomtd->cle, value: 0); |
89 | return 0; |
90 | |
91 | case NAND_OP_ADDR_INSTR: |
92 | gpio_nand_dosync(gpiomtd); |
93 | gpiod_set_value(desc: gpiomtd->ale, value: 1); |
94 | gpio_nand_dosync(gpiomtd); |
95 | for (i = 0; i < instr->ctx.addr.naddrs; i++) |
96 | writeb(val: instr->ctx.addr.addrs[i], addr: gpiomtd->io); |
97 | gpio_nand_dosync(gpiomtd); |
98 | gpiod_set_value(desc: gpiomtd->ale, value: 0); |
99 | return 0; |
100 | |
101 | case NAND_OP_DATA_IN_INSTR: |
102 | gpio_nand_dosync(gpiomtd); |
103 | if ((chip->options & NAND_BUSWIDTH_16) && |
104 | !instr->ctx.data.force_8bit) |
105 | ioread16_rep(port: gpiomtd->io, buf: instr->ctx.data.buf.in, |
106 | count: instr->ctx.data.len / 2); |
107 | else |
108 | ioread8_rep(port: gpiomtd->io, buf: instr->ctx.data.buf.in, |
109 | count: instr->ctx.data.len); |
110 | return 0; |
111 | |
112 | case NAND_OP_DATA_OUT_INSTR: |
113 | gpio_nand_dosync(gpiomtd); |
114 | if ((chip->options & NAND_BUSWIDTH_16) && |
115 | !instr->ctx.data.force_8bit) |
116 | iowrite16_rep(port: gpiomtd->io, buf: instr->ctx.data.buf.out, |
117 | count: instr->ctx.data.len / 2); |
118 | else |
119 | iowrite8_rep(port: gpiomtd->io, buf: instr->ctx.data.buf.out, |
120 | count: instr->ctx.data.len); |
121 | return 0; |
122 | |
123 | case NAND_OP_WAITRDY_INSTR: |
124 | if (!gpiomtd->rdy) |
125 | return nand_soft_waitrdy(chip, timeout_ms: instr->ctx.waitrdy.timeout_ms); |
126 | |
127 | return nand_gpio_waitrdy(chip, gpiod: gpiomtd->rdy, |
128 | timeout_ms: instr->ctx.waitrdy.timeout_ms); |
129 | |
130 | default: |
131 | return -EINVAL; |
132 | } |
133 | |
134 | return 0; |
135 | } |
136 | |
137 | static int gpio_nand_exec_op(struct nand_chip *chip, |
138 | const struct nand_operation *op, |
139 | bool check_only) |
140 | { |
141 | struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd: nand_to_mtd(chip)); |
142 | unsigned int i; |
143 | int ret = 0; |
144 | |
145 | if (check_only) |
146 | return 0; |
147 | |
148 | gpio_nand_dosync(gpiomtd); |
149 | gpiod_set_value(desc: gpiomtd->nce, value: 0); |
150 | for (i = 0; i < op->ninstrs; i++) { |
151 | ret = gpio_nand_exec_instr(chip, instr: &op->instrs[i]); |
152 | if (ret) |
153 | break; |
154 | |
155 | if (op->instrs[i].delay_ns) |
156 | ndelay(op->instrs[i].delay_ns); |
157 | } |
158 | gpio_nand_dosync(gpiomtd); |
159 | gpiod_set_value(desc: gpiomtd->nce, value: 1); |
160 | |
161 | return ret; |
162 | } |
163 | |
164 | static int gpio_nand_attach_chip(struct nand_chip *chip) |
165 | { |
166 | if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT && |
167 | chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) |
168 | chip->ecc.algo = NAND_ECC_ALGO_HAMMING; |
169 | |
170 | return 0; |
171 | } |
172 | |
173 | static const struct nand_controller_ops gpio_nand_ops = { |
174 | .exec_op = gpio_nand_exec_op, |
175 | .attach_chip = gpio_nand_attach_chip, |
176 | }; |
177 | |
178 | #ifdef CONFIG_OF |
179 | static const struct of_device_id gpio_nand_id_table[] = { |
180 | { .compatible = "gpio-control-nand" }, |
181 | {} |
182 | }; |
183 | MODULE_DEVICE_TABLE(of, gpio_nand_id_table); |
184 | |
185 | static int gpio_nand_get_config_of(const struct device *dev, |
186 | struct gpio_nand_platdata *plat) |
187 | { |
188 | u32 val; |
189 | |
190 | if (!dev->of_node) |
191 | return -ENODEV; |
192 | |
193 | if (!of_property_read_u32(np: dev->of_node, propname: "bank-width" , out_value: &val)) { |
194 | if (val == 2) { |
195 | plat->options |= NAND_BUSWIDTH_16; |
196 | } else if (val != 1) { |
197 | dev_err(dev, "invalid bank-width %u\n" , val); |
198 | return -EINVAL; |
199 | } |
200 | } |
201 | |
202 | if (!of_property_read_u32(np: dev->of_node, propname: "chip-delay" , out_value: &val)) |
203 | plat->chip_delay = val; |
204 | |
205 | return 0; |
206 | } |
207 | |
208 | static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev) |
209 | { |
210 | struct resource *r; |
211 | u64 addr; |
212 | |
213 | if (of_property_read_u64(np: pdev->dev.of_node, |
214 | propname: "gpio-control-nand,io-sync-reg" , out_value: &addr)) |
215 | return NULL; |
216 | |
217 | r = devm_kzalloc(dev: &pdev->dev, size: sizeof(*r), GFP_KERNEL); |
218 | if (!r) |
219 | return NULL; |
220 | |
221 | r->start = addr; |
222 | r->end = r->start + 0x3; |
223 | r->flags = IORESOURCE_MEM; |
224 | |
225 | return r; |
226 | } |
227 | #else /* CONFIG_OF */ |
228 | static inline int gpio_nand_get_config_of(const struct device *dev, |
229 | struct gpio_nand_platdata *plat) |
230 | { |
231 | return -ENOSYS; |
232 | } |
233 | |
234 | static inline struct resource * |
235 | gpio_nand_get_io_sync_of(struct platform_device *pdev) |
236 | { |
237 | return NULL; |
238 | } |
239 | #endif /* CONFIG_OF */ |
240 | |
241 | static inline int gpio_nand_get_config(const struct device *dev, |
242 | struct gpio_nand_platdata *plat) |
243 | { |
244 | int ret = gpio_nand_get_config_of(dev, plat); |
245 | |
246 | if (!ret) |
247 | return ret; |
248 | |
249 | if (dev_get_platdata(dev)) { |
250 | memcpy(plat, dev_get_platdata(dev), sizeof(*plat)); |
251 | return 0; |
252 | } |
253 | |
254 | return -EINVAL; |
255 | } |
256 | |
257 | static inline struct resource * |
258 | gpio_nand_get_io_sync(struct platform_device *pdev) |
259 | { |
260 | struct resource *r = gpio_nand_get_io_sync_of(pdev); |
261 | |
262 | if (r) |
263 | return r; |
264 | |
265 | return platform_get_resource(pdev, IORESOURCE_MEM, 1); |
266 | } |
267 | |
268 | static void gpio_nand_remove(struct platform_device *pdev) |
269 | { |
270 | struct gpiomtd *gpiomtd = platform_get_drvdata(pdev); |
271 | struct nand_chip *chip = &gpiomtd->nand_chip; |
272 | int ret; |
273 | |
274 | ret = mtd_device_unregister(master: nand_to_mtd(chip)); |
275 | WARN_ON(ret); |
276 | nand_cleanup(chip); |
277 | |
278 | /* Enable write protection and disable the chip */ |
279 | if (gpiomtd->nwp && !IS_ERR(ptr: gpiomtd->nwp)) |
280 | gpiod_set_value(desc: gpiomtd->nwp, value: 0); |
281 | if (gpiomtd->nce && !IS_ERR(ptr: gpiomtd->nce)) |
282 | gpiod_set_value(desc: gpiomtd->nce, value: 0); |
283 | } |
284 | |
285 | static int gpio_nand_probe(struct platform_device *pdev) |
286 | { |
287 | struct gpiomtd *gpiomtd; |
288 | struct nand_chip *chip; |
289 | struct mtd_info *mtd; |
290 | struct resource *res; |
291 | struct device *dev = &pdev->dev; |
292 | int ret = 0; |
293 | |
294 | if (!dev->of_node && !dev_get_platdata(dev)) |
295 | return -EINVAL; |
296 | |
297 | gpiomtd = devm_kzalloc(dev, size: sizeof(*gpiomtd), GFP_KERNEL); |
298 | if (!gpiomtd) |
299 | return -ENOMEM; |
300 | |
301 | chip = &gpiomtd->nand_chip; |
302 | |
303 | gpiomtd->io = devm_platform_ioremap_resource(pdev, index: 0); |
304 | if (IS_ERR(ptr: gpiomtd->io)) |
305 | return PTR_ERR(ptr: gpiomtd->io); |
306 | |
307 | res = gpio_nand_get_io_sync(pdev); |
308 | if (res) { |
309 | gpiomtd->io_sync = devm_ioremap_resource(dev, res); |
310 | if (IS_ERR(ptr: gpiomtd->io_sync)) |
311 | return PTR_ERR(ptr: gpiomtd->io_sync); |
312 | } |
313 | |
314 | ret = gpio_nand_get_config(dev, plat: &gpiomtd->plat); |
315 | if (ret) |
316 | return ret; |
317 | |
318 | /* Just enable the chip */ |
319 | gpiomtd->nce = devm_gpiod_get_optional(dev, con_id: "nce" , flags: GPIOD_OUT_HIGH); |
320 | if (IS_ERR(ptr: gpiomtd->nce)) |
321 | return PTR_ERR(ptr: gpiomtd->nce); |
322 | |
323 | /* We disable write protection once we know probe() will succeed */ |
324 | gpiomtd->nwp = devm_gpiod_get_optional(dev, con_id: "nwp" , flags: GPIOD_OUT_LOW); |
325 | if (IS_ERR(ptr: gpiomtd->nwp)) { |
326 | ret = PTR_ERR(ptr: gpiomtd->nwp); |
327 | goto out_ce; |
328 | } |
329 | |
330 | gpiomtd->ale = devm_gpiod_get(dev, con_id: "ale" , flags: GPIOD_OUT_LOW); |
331 | if (IS_ERR(ptr: gpiomtd->ale)) { |
332 | ret = PTR_ERR(ptr: gpiomtd->ale); |
333 | goto out_ce; |
334 | } |
335 | |
336 | gpiomtd->cle = devm_gpiod_get(dev, con_id: "cle" , flags: GPIOD_OUT_LOW); |
337 | if (IS_ERR(ptr: gpiomtd->cle)) { |
338 | ret = PTR_ERR(ptr: gpiomtd->cle); |
339 | goto out_ce; |
340 | } |
341 | |
342 | gpiomtd->rdy = devm_gpiod_get_optional(dev, con_id: "rdy" , flags: GPIOD_IN); |
343 | if (IS_ERR(ptr: gpiomtd->rdy)) { |
344 | ret = PTR_ERR(ptr: gpiomtd->rdy); |
345 | goto out_ce; |
346 | } |
347 | |
348 | nand_controller_init(nfc: &gpiomtd->base); |
349 | gpiomtd->base.ops = &gpio_nand_ops; |
350 | |
351 | nand_set_flash_node(chip, np: pdev->dev.of_node); |
352 | chip->options = gpiomtd->plat.options; |
353 | chip->controller = &gpiomtd->base; |
354 | |
355 | mtd = nand_to_mtd(chip); |
356 | mtd->dev.parent = dev; |
357 | |
358 | platform_set_drvdata(pdev, data: gpiomtd); |
359 | |
360 | /* Disable write protection, if wired up */ |
361 | if (gpiomtd->nwp && !IS_ERR(ptr: gpiomtd->nwp)) |
362 | gpiod_direction_output(desc: gpiomtd->nwp, value: 1); |
363 | |
364 | /* |
365 | * This driver assumes that the default ECC engine should be TYPE_SOFT. |
366 | * Set ->engine_type before registering the NAND devices in order to |
367 | * provide a driver specific default value. |
368 | */ |
369 | chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; |
370 | |
371 | ret = nand_scan(chip, max_chips: 1); |
372 | if (ret) |
373 | goto err_wp; |
374 | |
375 | if (gpiomtd->plat.adjust_parts) |
376 | gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size); |
377 | |
378 | ret = mtd_device_register(mtd, gpiomtd->plat.parts, |
379 | gpiomtd->plat.num_parts); |
380 | if (!ret) |
381 | return 0; |
382 | |
383 | err_wp: |
384 | if (gpiomtd->nwp && !IS_ERR(ptr: gpiomtd->nwp)) |
385 | gpiod_set_value(desc: gpiomtd->nwp, value: 0); |
386 | out_ce: |
387 | if (gpiomtd->nce && !IS_ERR(ptr: gpiomtd->nce)) |
388 | gpiod_set_value(desc: gpiomtd->nce, value: 0); |
389 | |
390 | return ret; |
391 | } |
392 | |
393 | static struct platform_driver gpio_nand_driver = { |
394 | .probe = gpio_nand_probe, |
395 | .remove_new = gpio_nand_remove, |
396 | .driver = { |
397 | .name = "gpio-nand" , |
398 | .of_match_table = of_match_ptr(gpio_nand_id_table), |
399 | }, |
400 | }; |
401 | |
402 | module_platform_driver(gpio_nand_driver); |
403 | |
404 | MODULE_LICENSE("GPL" ); |
405 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>" ); |
406 | MODULE_DESCRIPTION("GPIO NAND Driver" ); |
407 | |