Root/
Source at commit 54e2765ab500d482e019cbb4f0075933919a7836 created 13 years 4 months ago. By Maarten ter Huurne, MTD: NAND: JZ4740: Multi-bank support with autodetection | |
---|---|
1 | /* |
2 | * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> |
3 | * JZ4740 SoC NAND controller driver |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License as published by the |
7 | * Free Software Foundation; either version 2 of the License, or (at your |
8 | * option) any later version. |
9 | * |
10 | * You should have received a copy of the GNU General Public License along |
11 | * with this program; if not, write to the Free Software Foundation, Inc., |
12 | * 675 Mass Ave, Cambridge, MA 02139, USA. |
13 | * |
14 | */ |
15 | |
16 | #include <linux/ioport.h> |
17 | #include <linux/kernel.h> |
18 | #include <linux/module.h> |
19 | #include <linux/platform_device.h> |
20 | #include <linux/slab.h> |
21 | |
22 | #include <linux/mtd/mtd.h> |
23 | #include <linux/mtd/nand.h> |
24 | #include <linux/mtd/partitions.h> |
25 | |
26 | #include <linux/gpio.h> |
27 | |
28 | #include <asm/mach-jz4740/jz4740_nand.h> |
29 | |
30 | #define JZ_REG_NAND_CTRL 0x50 |
31 | #define JZ_REG_NAND_ECC_CTRL 0x100 |
32 | #define JZ_REG_NAND_DATA 0x104 |
33 | #define JZ_REG_NAND_PAR0 0x108 |
34 | #define JZ_REG_NAND_PAR1 0x10C |
35 | #define JZ_REG_NAND_PAR2 0x110 |
36 | #define JZ_REG_NAND_IRQ_STAT 0x114 |
37 | #define JZ_REG_NAND_IRQ_CTRL 0x118 |
38 | #define JZ_REG_NAND_ERR(x) (0x11C + ((x) << 2)) |
39 | |
40 | #define JZ_NAND_ECC_CTRL_PAR_READY BIT(4) |
41 | #define JZ_NAND_ECC_CTRL_ENCODING BIT(3) |
42 | #define JZ_NAND_ECC_CTRL_RS BIT(2) |
43 | #define JZ_NAND_ECC_CTRL_RESET BIT(1) |
44 | #define JZ_NAND_ECC_CTRL_ENABLE BIT(0) |
45 | |
46 | #define JZ_NAND_STATUS_ERR_COUNT (BIT(31) | BIT(30) | BIT(29)) |
47 | #define JZ_NAND_STATUS_PAD_FINISH BIT(4) |
48 | #define JZ_NAND_STATUS_DEC_FINISH BIT(3) |
49 | #define JZ_NAND_STATUS_ENC_FINISH BIT(2) |
50 | #define JZ_NAND_STATUS_UNCOR_ERROR BIT(1) |
51 | #define JZ_NAND_STATUS_ERROR BIT(0) |
52 | |
53 | #define JZ_NAND_CTRL_ENABLE_CHIP(x) BIT((x) << 1) |
54 | #define JZ_NAND_CTRL_ASSERT_CHIP(x) BIT(((x) << 1) + 1) |
55 | #define JZ_NAND_CTRL_ASSERT_CHIP_MASK 0xaa |
56 | |
57 | #define JZ_NAND_MEM_CMD_OFFSET 0x08000 |
58 | #define JZ_NAND_MEM_ADDR_OFFSET 0x10000 |
59 | |
60 | struct jz_nand { |
61 | struct mtd_info mtd; |
62 | struct nand_chip chip; |
63 | void __iomem *base; |
64 | struct resource *mem; |
65 | |
66 | unsigned char banks[JZ_NAND_NUM_BANKS]; |
67 | void __iomem *bank_base[JZ_NAND_NUM_BANKS]; |
68 | struct resource *bank_mem[JZ_NAND_NUM_BANKS]; |
69 | |
70 | int selected_bank; |
71 | |
72 | struct jz_nand_platform_data *pdata; |
73 | bool is_reading; |
74 | }; |
75 | |
76 | static inline struct jz_nand *mtd_to_jz_nand(struct mtd_info *mtd) |
77 | { |
78 | return container_of(mtd, struct jz_nand, mtd); |
79 | } |
80 | |
81 | static void jz_nand_select_chip(struct mtd_info *mtd, int chipnr) |
82 | { |
83 | struct jz_nand *nand = mtd_to_jz_nand(mtd); |
84 | struct nand_chip *chip = mtd->priv; |
85 | uint32_t ctrl; |
86 | int banknr; |
87 | |
88 | ctrl = readl(nand->base + JZ_REG_NAND_CTRL); |
89 | ctrl &= ~JZ_NAND_CTRL_ASSERT_CHIP_MASK; |
90 | |
91 | if (chipnr == -1) { |
92 | banknr = -1; |
93 | } else { |
94 | banknr = nand->banks[chipnr] - 1; |
95 | chip->IO_ADDR_R = nand->bank_base[banknr]; |
96 | chip->IO_ADDR_W = nand->bank_base[banknr]; |
97 | } |
98 | writel(ctrl, nand->base + JZ_REG_NAND_CTRL); |
99 | |
100 | nand->selected_bank = banknr; |
101 | } |
102 | |
103 | static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) |
104 | { |
105 | struct jz_nand *nand = mtd_to_jz_nand(mtd); |
106 | struct nand_chip *chip = mtd->priv; |
107 | uint32_t reg; |
108 | void __iomem *bank_base = nand->bank_base[nand->selected_bank]; |
109 | |
110 | BUG_ON(nand->selected_bank < 0); |
111 | |
112 | if (ctrl & NAND_CTRL_CHANGE) { |
113 | BUG_ON((ctrl & NAND_ALE) && (ctrl & NAND_CLE)); |
114 | if (ctrl & NAND_ALE) |
115 | bank_base += JZ_NAND_MEM_ADDR_OFFSET; |
116 | else if (ctrl & NAND_CLE) |
117 | bank_base += JZ_NAND_MEM_CMD_OFFSET; |
118 | chip->IO_ADDR_W = bank_base; |
119 | |
120 | reg = readl(nand->base + JZ_REG_NAND_CTRL); |
121 | if (ctrl & NAND_NCE) |
122 | reg |= JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); |
123 | else |
124 | reg &= ~JZ_NAND_CTRL_ASSERT_CHIP(nand->selected_bank); |
125 | writel(reg, nand->base + JZ_REG_NAND_CTRL); |
126 | } |
127 | if (dat != NAND_CMD_NONE) |
128 | writeb(dat, chip->IO_ADDR_W); |
129 | } |
130 | |
131 | static int jz_nand_dev_ready(struct mtd_info *mtd) |
132 | { |
133 | struct jz_nand *nand = mtd_to_jz_nand(mtd); |
134 | return gpio_get_value_cansleep(nand->pdata->busy_gpio); |
135 | } |
136 | |
137 | static void jz_nand_hwctl(struct mtd_info *mtd, int mode) |
138 | { |
139 | struct jz_nand *nand = mtd_to_jz_nand(mtd); |
140 | uint32_t reg; |
141 | |
142 | writel(0, nand->base + JZ_REG_NAND_IRQ_STAT); |
143 | reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); |
144 | |
145 | reg |= JZ_NAND_ECC_CTRL_RESET; |
146 | reg |= JZ_NAND_ECC_CTRL_ENABLE; |
147 | reg |= JZ_NAND_ECC_CTRL_RS; |
148 | |
149 | switch (mode) { |
150 | case NAND_ECC_READ: |
151 | reg &= ~JZ_NAND_ECC_CTRL_ENCODING; |
152 | nand->is_reading = true; |
153 | break; |
154 | case NAND_ECC_WRITE: |
155 | reg |= JZ_NAND_ECC_CTRL_ENCODING; |
156 | nand->is_reading = false; |
157 | break; |
158 | default: |
159 | break; |
160 | } |
161 | |
162 | writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); |
163 | } |
164 | |
165 | static int jz_nand_calculate_ecc_rs(struct mtd_info *mtd, const uint8_t *dat, |
166 | uint8_t *ecc_code) |
167 | { |
168 | struct jz_nand *nand = mtd_to_jz_nand(mtd); |
169 | uint32_t reg, status; |
170 | int i; |
171 | unsigned int timeout = 1000; |
172 | static uint8_t empty_block_ecc[] = {0xcd, 0x9d, 0x90, 0x58, 0xf4, |
173 | 0x8b, 0xff, 0xb7, 0x6f}; |
174 | |
175 | if (nand->is_reading) |
176 | return 0; |
177 | |
178 | do { |
179 | status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); |
180 | } while (!(status & JZ_NAND_STATUS_ENC_FINISH) && --timeout); |
181 | |
182 | if (timeout == 0) |
183 | return -1; |
184 | |
185 | reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); |
186 | reg &= ~JZ_NAND_ECC_CTRL_ENABLE; |
187 | writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); |
188 | |
189 | for (i = 0; i < 9; ++i) |
190 | ecc_code[i] = readb(nand->base + JZ_REG_NAND_PAR0 + i); |
191 | |
192 | /* If the written data is completly 0xff, we also want to write 0xff as |
193 | * ecc, otherwise we will get in trouble when doing subpage writes. */ |
194 | if (memcmp(ecc_code, empty_block_ecc, 9) == 0) |
195 | memset(ecc_code, 0xff, 9); |
196 | |
197 | return 0; |
198 | } |
199 | |
200 | static void jz_nand_correct_data(uint8_t *dat, int index, int mask) |
201 | { |
202 | int offset = index & 0x7; |
203 | uint16_t data; |
204 | |
205 | index += (index >> 3); |
206 | |
207 | data = dat[index]; |
208 | data |= dat[index+1] << 8; |
209 | |
210 | mask ^= (data >> offset) & 0x1ff; |
211 | data &= ~(0x1ff << offset); |
212 | data |= (mask << offset); |
213 | |
214 | dat[index] = data & 0xff; |
215 | dat[index+1] = (data >> 8) & 0xff; |
216 | } |
217 | |
218 | static int jz_nand_correct_ecc_rs(struct mtd_info *mtd, uint8_t *dat, |
219 | uint8_t *read_ecc, uint8_t *calc_ecc) |
220 | { |
221 | struct jz_nand *nand = mtd_to_jz_nand(mtd); |
222 | int i, error_count, index; |
223 | uint32_t reg, status, error; |
224 | uint32_t t; |
225 | unsigned int timeout = 1000; |
226 | |
227 | t = read_ecc[0]; |
228 | |
229 | if (t == 0xff) { |
230 | for (i = 1; i < 9; ++i) |
231 | t &= read_ecc[i]; |
232 | |
233 | t &= dat[0]; |
234 | t &= dat[nand->chip.ecc.size / 2]; |
235 | t &= dat[nand->chip.ecc.size - 1]; |
236 | |
237 | if (t == 0xff) { |
238 | for (i = 1; i < nand->chip.ecc.size - 1; ++i) |
239 | t &= dat[i]; |
240 | if (t == 0xff) |
241 | return 0; |
242 | } |
243 | } |
244 | |
245 | for (i = 0; i < 9; ++i) |
246 | writeb(read_ecc[i], nand->base + JZ_REG_NAND_PAR0 + i); |
247 | |
248 | reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); |
249 | reg |= JZ_NAND_ECC_CTRL_PAR_READY; |
250 | writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); |
251 | |
252 | do { |
253 | status = readl(nand->base + JZ_REG_NAND_IRQ_STAT); |
254 | } while (!(status & JZ_NAND_STATUS_DEC_FINISH) && --timeout); |
255 | |
256 | if (timeout == 0) |
257 | return -1; |
258 | |
259 | reg = readl(nand->base + JZ_REG_NAND_ECC_CTRL); |
260 | reg &= ~JZ_NAND_ECC_CTRL_ENABLE; |
261 | writel(reg, nand->base + JZ_REG_NAND_ECC_CTRL); |
262 | |
263 | if (status & JZ_NAND_STATUS_ERROR) { |
264 | if (status & JZ_NAND_STATUS_UNCOR_ERROR) |
265 | return -1; |
266 | |
267 | error_count = (status & JZ_NAND_STATUS_ERR_COUNT) >> 29; |
268 | |
269 | for (i = 0; i < error_count; ++i) { |
270 | error = readl(nand->base + JZ_REG_NAND_ERR(i)); |
271 | index = ((error >> 16) & 0x1ff) - 1; |
272 | if (index >= 0 && index < 512) |
273 | jz_nand_correct_data(dat, index, error & 0x1ff); |
274 | } |
275 | |
276 | return error_count; |
277 | } |
278 | |
279 | return 0; |
280 | } |
281 | |
282 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
283 | static const char *part_probes[] = {"cmdline", NULL}; |
284 | #endif |
285 | |
286 | static int jz_nand_ioremap_resource(struct platform_device *pdev, |
287 | const char *name, struct resource **res, void *__iomem *base) |
288 | { |
289 | int ret; |
290 | |
291 | *res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); |
292 | if (!*res) { |
293 | dev_err(&pdev->dev, "Failed to get platform %s memory\n", name); |
294 | ret = -ENXIO; |
295 | goto err; |
296 | } |
297 | |
298 | *res = request_mem_region((*res)->start, resource_size(*res), |
299 | pdev->name); |
300 | if (!*res) { |
301 | dev_err(&pdev->dev, "Failed to request %s memory region\n", name); |
302 | ret = -EBUSY; |
303 | goto err; |
304 | } |
305 | |
306 | *base = ioremap((*res)->start, resource_size(*res)); |
307 | if (!*base) { |
308 | dev_err(&pdev->dev, "Failed to ioremap %s memory region\n", name); |
309 | ret = -EBUSY; |
310 | goto err_release_mem; |
311 | } |
312 | |
313 | return 0; |
314 | |
315 | err_release_mem: |
316 | release_mem_region((*res)->start, resource_size(*res)); |
317 | err: |
318 | *res = NULL; |
319 | *base = NULL; |
320 | return ret; |
321 | } |
322 | |
323 | static inline void jz_nand_iounmap_resource(struct resource *res, void __iomem *base) |
324 | { |
325 | iounmap(base); |
326 | release_mem_region(res->start, resource_size(res)); |
327 | } |
328 | |
329 | static int __devinit jz_nand_detect_bank(struct platform_device *pdev, struct jz_nand *nand, unsigned char bank, size_t chipnr, uint8_t *nand_maf_id, uint8_t *nand_dev_id) { |
330 | int ret; |
331 | int gpio; |
332 | char gpio_name[9]; |
333 | char res_name[6]; |
334 | uint32_t ctrl; |
335 | struct mtd_info *mtd = &nand->mtd; |
336 | struct nand_chip *chip = &nand->chip; |
337 | |
338 | /* Request GPIO port. */ |
339 | gpio = JZ_GPIO_MEM_CS0 + bank - 1; |
340 | sprintf(gpio_name, "NAND CS%d", bank); |
341 | ret = gpio_request(gpio, gpio_name); |
342 | if (ret) { |
343 | dev_warn(&pdev->dev, |
344 | "Failed to request %s gpio %d: %d\n", |
345 | gpio_name, gpio, ret); |
346 | goto notfound_gpio; |
347 | } |
348 | |
349 | /* Request I/O resource. */ |
350 | sprintf(res_name, "bank%d", bank); |
351 | ret = jz_nand_ioremap_resource(pdev, res_name, |
352 | &nand->bank_mem[bank - 1], |
353 | &nand->bank_base[bank - 1]); |
354 | if (ret) |
355 | goto notfound_resource; |
356 | |
357 | /* Enable chip in bank. */ |
358 | jz_gpio_set_function(gpio, JZ_GPIO_FUNC_MEM_CS0); |
359 | ctrl = readl(nand->base + JZ_REG_NAND_CTRL); |
360 | ctrl |= JZ_NAND_CTRL_ENABLE_CHIP(bank - 1); |
361 | writel(ctrl, nand->base + JZ_REG_NAND_CTRL); |
362 | |
363 | if (chipnr == 0) { |
364 | /* Detect first chip. */ |
365 | ret = nand_scan_ident(mtd, 1, NULL); |
366 | if (ret) |
367 | goto notfound_id; |
368 | |
369 | /* Retrieve the IDs from the first chip. */ |
370 | chip->select_chip(mtd, 0); |
371 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); |
372 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
373 | *nand_maf_id = chip->read_byte(mtd); |
374 | *nand_dev_id = chip->read_byte(mtd); |
375 | } else { |
376 | /* Detect additional chip. */ |
377 | chip->select_chip(mtd, chipnr); |
378 | chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); |
379 | chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); |
380 | if (*nand_maf_id != chip->read_byte(mtd) |
381 | || *nand_dev_id != chip->read_byte(mtd)) { |
382 | ret = -ENODEV; |
383 | goto notfound_id; |
384 | } |
385 | |
386 | /* Update size of the MTD. */ |
387 | chip->numchips++; |
388 | mtd->size += chip->chipsize; |
389 | } |
390 | |
391 | dev_info(&pdev->dev, "Found chip %i on bank %i\n", chipnr, bank); |
392 | return 0; |
393 | |
394 | notfound_id: |
395 | dev_info(&pdev->dev, "No chip found on bank %i\n", bank); |
396 | ctrl &= ~(JZ_NAND_CTRL_ENABLE_CHIP(bank - 1)); |
397 | writel(ctrl, nand->base + JZ_REG_NAND_CTRL); |
398 | jz_gpio_set_function(gpio, JZ_GPIO_FUNC_NONE); |
399 | jz_nand_iounmap_resource(nand->bank_mem[bank - 1], |
400 | nand->bank_base[bank - 1]); |
401 | notfound_resource: |
402 | gpio_free(gpio); |
403 | notfound_gpio: |
404 | return ret; |
405 | } |
406 | |
407 | static int __devinit jz_nand_probe(struct platform_device *pdev) |
408 | { |
409 | int ret; |
410 | struct jz_nand *nand; |
411 | struct nand_chip *chip; |
412 | struct mtd_info *mtd; |
413 | struct jz_nand_platform_data *pdata = pdev->dev.platform_data; |
414 | #ifdef CONFIG_MTD_PARTITIONS |
415 | struct mtd_partition *partition_info; |
416 | int num_partitions = 0; |
417 | #endif |
418 | size_t chipnr, bank_idx; |
419 | uint8_t nand_maf_id = 0, nand_dev_id = 0; |
420 | |
421 | nand = kzalloc(sizeof(*nand), GFP_KERNEL); |
422 | if (!nand) { |
423 | dev_err(&pdev->dev, "Failed to allocate device structure.\n"); |
424 | return -ENOMEM; |
425 | } |
426 | |
427 | ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base); |
428 | if (ret) |
429 | goto err_free; |
430 | |
431 | if (pdata && gpio_is_valid(pdata->busy_gpio)) { |
432 | ret = gpio_request(pdata->busy_gpio, "NAND busy pin"); |
433 | if (ret) { |
434 | dev_err(&pdev->dev, |
435 | "Failed to request busy gpio %d: %d\n", |
436 | pdata->busy_gpio, ret); |
437 | goto err_iounmap_mmio; |
438 | } |
439 | } |
440 | |
441 | mtd = &nand->mtd; |
442 | chip = &nand->chip; |
443 | mtd->priv = chip; |
444 | mtd->owner = THIS_MODULE; |
445 | mtd->name = "jz4740-nand"; |
446 | |
447 | chip->ecc.hwctl = jz_nand_hwctl; |
448 | chip->ecc.calculate = jz_nand_calculate_ecc_rs; |
449 | chip->ecc.correct = jz_nand_correct_ecc_rs; |
450 | chip->ecc.mode = NAND_ECC_HW_OOB_FIRST; |
451 | chip->ecc.size = 512; |
452 | chip->ecc.bytes = 9; |
453 | |
454 | if (pdata) |
455 | chip->ecc.layout = pdata->ecc_layout; |
456 | |
457 | chip->chip_delay = 50; |
458 | chip->cmd_ctrl = jz_nand_cmd_ctrl; |
459 | chip->select_chip = jz_nand_select_chip; |
460 | |
461 | if (pdata && gpio_is_valid(pdata->busy_gpio)) |
462 | chip->dev_ready = jz_nand_dev_ready; |
463 | |
464 | nand->pdata = pdata; |
465 | platform_set_drvdata(pdev, nand); |
466 | |
467 | /* We are going to autodetect NAND chips in the banks specified in the |
468 | * platform data. Although nand_scan_ident() can detect multiple chips, |
469 | * it requires those chips to be numbered consecuitively, which is not |
470 | * always the case for external memory banks. And a fixed chip-to-bank |
471 | * mapping is not practical either, since for example Dingoo units |
472 | * produced at different times have NAND chips in different banks. |
473 | */ |
474 | chipnr = 0; |
475 | for (bank_idx = 0; bank_idx < JZ_NAND_NUM_BANKS; bank_idx++) { |
476 | unsigned char bank; |
477 | |
478 | /* If there is no platform data, look for NAND in bank 1, |
479 | * which is the most likely bank since it is the only one |
480 | * that can be booted from. |
481 | */ |
482 | bank = pdata ? pdata->banks[bank_idx] : bank_idx ^ 1; |
483 | if (bank == 0) |
484 | break; |
485 | if (bank > JZ_NAND_NUM_BANKS) { |
486 | dev_warn(&pdev->dev, |
487 | "Skipping non-existing bank: %d\n", bank); |
488 | continue; |
489 | } |
490 | /* The detection routine will directly or indirectly call |
491 | * jz_nand_select_chip(), so nand->banks has to contain the |
492 | * bank we're checking. |
493 | */ |
494 | nand->banks[chipnr] = bank; |
495 | if (jz_nand_detect_bank(pdev, nand, bank, chipnr, |
496 | &nand_maf_id, &nand_dev_id) == 0) |
497 | chipnr++; |
498 | else |
499 | nand->banks[chipnr] = 0; |
500 | } |
501 | if (chipnr == 0) { |
502 | dev_err(&pdev->dev, "No NAND chips found\n"); |
503 | goto err_gpio_busy; |
504 | } |
505 | |
506 | if (pdata && pdata->ident_callback) { |
507 | pdata->ident_callback(pdev, chip, &pdata->partitions, |
508 | &pdata->num_partitions); |
509 | } |
510 | |
511 | ret = nand_scan_tail(mtd); |
512 | if (ret) { |
513 | dev_err(&pdev->dev, "Failed to scan NAND\n"); |
514 | goto err_unclaim_banks; |
515 | } |
516 | |
517 | #ifdef CONFIG_MTD_PARTITIONS |
518 | #ifdef CONFIG_MTD_CMDLINE_PARTS |
519 | num_partitions = parse_mtd_partitions(mtd, part_probes, |
520 | &partition_info, 0); |
521 | #endif |
522 | if (num_partitions <= 0 && pdata) { |
523 | num_partitions = pdata->num_partitions; |
524 | partition_info = pdata->partitions; |
525 | } |
526 | |
527 | if (num_partitions > 0) |
528 | ret = add_mtd_partitions(mtd, partition_info, num_partitions); |
529 | else |
530 | #endif |
531 | ret = add_mtd_device(mtd) ? -ENODEV : 0; |
532 | |
533 | if (ret) { |
534 | dev_err(&pdev->dev, "Failed to add mtd device\n"); |
535 | goto err_nand_release; |
536 | } |
537 | |
538 | dev_info(&pdev->dev, "Successfully registered JZ4740 NAND driver\n"); |
539 | |
540 | return 0; |
541 | |
542 | err_nand_release: |
543 | nand_release(mtd); |
544 | err_unclaim_banks: |
545 | while (chipnr--) { |
546 | unsigned char bank = nand->banks[chipnr]; |
547 | gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); |
548 | jz_nand_iounmap_resource(nand->bank_mem[bank - 1], |
549 | nand->bank_base[bank - 1]); |
550 | } |
551 | writel(0, nand->base + JZ_REG_NAND_CTRL); |
552 | err_gpio_busy: |
553 | if (pdata && gpio_is_valid(pdata->busy_gpio)) |
554 | gpio_free(pdata->busy_gpio); |
555 | platform_set_drvdata(pdev, NULL); |
556 | err_iounmap_mmio: |
557 | jz_nand_iounmap_resource(nand->mem, nand->base); |
558 | err_free: |
559 | kfree(nand); |
560 | return ret; |
561 | } |
562 | |
563 | static int __devexit jz_nand_remove(struct platform_device *pdev) |
564 | { |
565 | struct jz_nand *nand = platform_get_drvdata(pdev); |
566 | struct jz_nand_platform_data *pdata = pdev->dev.platform_data; |
567 | size_t i; |
568 | |
569 | nand_release(&nand->mtd); |
570 | |
571 | /* Deassert and disable all chips */ |
572 | writel(0, nand->base + JZ_REG_NAND_CTRL); |
573 | |
574 | for (i = 0; i < JZ_NAND_NUM_BANKS; ++i) { |
575 | unsigned char bank = nand->banks[i]; |
576 | if (bank != 0) { |
577 | jz_nand_iounmap_resource(nand->bank_mem[bank - 1], |
578 | nand->bank_base[bank - 1]); |
579 | gpio_free(JZ_GPIO_MEM_CS0 + bank - 1); |
580 | } |
581 | } |
582 | if (pdata && gpio_is_valid(pdata->busy_gpio)) |
583 | gpio_free(pdata->busy_gpio); |
584 | |
585 | jz_nand_iounmap_resource(nand->mem, nand->base); |
586 | |
587 | platform_set_drvdata(pdev, NULL); |
588 | kfree(nand); |
589 | |
590 | return 0; |
591 | } |
592 | |
593 | static struct platform_driver jz_nand_driver = { |
594 | .probe = jz_nand_probe, |
595 | .remove = __devexit_p(jz_nand_remove), |
596 | .driver = { |
597 | .name = "jz4740-nand", |
598 | .owner = THIS_MODULE, |
599 | }, |
600 | }; |
601 | |
602 | static int __init jz_nand_init(void) |
603 | { |
604 | return platform_driver_register(&jz_nand_driver); |
605 | } |
606 | module_init(jz_nand_init); |
607 | |
608 | static void __exit jz_nand_exit(void) |
609 | { |
610 | platform_driver_unregister(&jz_nand_driver); |
611 | } |
612 | module_exit(jz_nand_exit); |
613 | |
614 | MODULE_LICENSE("GPL"); |
615 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
616 | MODULE_DESCRIPTION("NAND controller driver for JZ4740 SoC"); |
617 | MODULE_ALIAS("platform:jz4740-nand"); |
618 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9