Commit 30f9f2fb7ba032665c8cea7694c815f18ed47a34
Committed by
Artem Bityutskiy
1 parent
2a0a288ec2
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
mtd: denali: add a DT driver
Add a device tree version of the Denali NAND driver. Based on an original patch from Jamie Iles to add a MMIO version of this driver. Signed-off-by: Dinh Nguyen <dinguyen@altera.com> Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Showing 5 changed files with 200 additions and 1 deletions Side-by-side Diff
Documentation/devicetree/bindings/mtd/denali-nand.txt
1 | +* Denali NAND controller | |
2 | + | |
3 | +Required properties: | |
4 | + - compatible : should be "denali,denali-nand-dt" | |
5 | + - reg : should contain registers location and length for data and reg. | |
6 | + - reg-names: Should contain the reg names "nand_data" and "denali_reg" | |
7 | + - interrupts : The interrupt number. | |
8 | + - dm-mask : DMA bit mask | |
9 | + | |
10 | +The device tree may optionally contain sub-nodes describing partitions of the | |
11 | +address space. See partition.txt for more detail. | |
12 | + | |
13 | +Examples: | |
14 | + | |
15 | +nand: nand@ff900000 { | |
16 | + #address-cells = <1>; | |
17 | + #size-cells = <1>; | |
18 | + compatible = "denali,denali-nand-dt"; | |
19 | + reg = <0xff900000 0x100000>, <0xffb80000 0x10000>; | |
20 | + reg-names = "nand_data", "denali_reg"; | |
21 | + interrupts = <0 144 4>; | |
22 | + dma-mask = <0xffffffff>; | |
23 | +}; |
drivers/mtd/nand/Kconfig
... | ... | @@ -69,7 +69,14 @@ |
69 | 69 | help |
70 | 70 | Enable the driver for NAND flash on Intel Moorestown, using the |
71 | 71 | Denali NAND controller core. |
72 | - | |
72 | + | |
73 | +config MTD_NAND_DENALI_DT | |
74 | + tristate "Support Denali NAND controller as a DT device" | |
75 | + depends on HAVE_CLK && MTD_NAND_DENALI | |
76 | + help | |
77 | + Enable the driver for NAND flash on platforms using a Denali NAND | |
78 | + controller as a DT device. | |
79 | + | |
73 | 80 | config MTD_NAND_DENALI_SCRATCH_REG_ADDR |
74 | 81 | hex "Denali NAND size scratch register address" |
75 | 82 | default "0xFF108018" |
drivers/mtd/nand/Makefile
... | ... | @@ -14,6 +14,7 @@ |
14 | 14 | obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o |
15 | 15 | obj-$(CONFIG_MTD_NAND_DENALI) += denali.o |
16 | 16 | obj-$(CONFIG_MTD_NAND_DENALI_PCI) += denali_pci.o |
17 | +obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o | |
17 | 18 | obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o |
18 | 19 | obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o |
19 | 20 | obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o |
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c
1 | +/* | |
2 | + * NAND Flash Controller Device Driver for DT | |
3 | + * | |
4 | + * Copyright © 2011, Picochip. | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify it | |
7 | + * under the terms and conditions of the GNU General Public License, | |
8 | + * version 2, as published by the Free Software Foundation. | |
9 | + * | |
10 | + * This program is distributed in the hope it will be useful, but WITHOUT | |
11 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 | + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
13 | + * more details. | |
14 | + */ | |
15 | +#include <linux/clk.h> | |
16 | +#include <linux/err.h> | |
17 | +#include <linux/io.h> | |
18 | +#include <linux/ioport.h> | |
19 | +#include <linux/kernel.h> | |
20 | +#include <linux/module.h> | |
21 | +#include <linux/platform_device.h> | |
22 | +#include <linux/of.h> | |
23 | +#include <linux/of_device.h> | |
24 | +#include <linux/slab.h> | |
25 | + | |
26 | +#include "denali.h" | |
27 | + | |
28 | +struct denali_dt { | |
29 | + struct denali_nand_info denali; | |
30 | + struct clk *clk; | |
31 | +}; | |
32 | + | |
33 | +static void __iomem *request_and_map(struct device *dev, | |
34 | + const struct resource *res) | |
35 | +{ | |
36 | + void __iomem *ptr; | |
37 | + | |
38 | + if (!devm_request_mem_region(dev, res->start, resource_size(res), | |
39 | + "denali-dt")) { | |
40 | + dev_err(dev, "unable to request %s\n", res->name); | |
41 | + return NULL; | |
42 | + } | |
43 | + | |
44 | + ptr = devm_ioremap_nocache(dev, res->start, resource_size(res)); | |
45 | + if (!res) | |
46 | + dev_err(dev, "ioremap_nocache of %s failed!", res->name); | |
47 | + | |
48 | + return ptr; | |
49 | +} | |
50 | + | |
51 | +static const struct of_device_id denali_nand_dt_ids[] = { | |
52 | + { .compatible = "denali,denali-nand-dt" }, | |
53 | + { /* sentinel */ } | |
54 | + }; | |
55 | + | |
56 | +MODULE_DEVICE_TABLE(of, denali_nand_dt_ids); | |
57 | + | |
58 | +static u64 denali_dma_mask; | |
59 | + | |
60 | +static int __devinit denali_dt_probe(struct platform_device *ofdev) | |
61 | +{ | |
62 | + struct resource *denali_reg, *nand_data; | |
63 | + struct denali_dt *dt; | |
64 | + struct denali_nand_info *denali; | |
65 | + int ret; | |
66 | + const struct of_device_id *of_id; | |
67 | + | |
68 | + of_id = of_match_device(denali_nand_dt_ids, &ofdev->dev); | |
69 | + if (of_id) { | |
70 | + ofdev->id_entry = of_id->data; | |
71 | + } else { | |
72 | + pr_err("Failed to find the right device id.\n"); | |
73 | + return -ENOMEM; | |
74 | + } | |
75 | + | |
76 | + dt = devm_kzalloc(&ofdev->dev, sizeof(*dt), GFP_KERNEL); | |
77 | + if (!dt) | |
78 | + return -ENOMEM; | |
79 | + denali = &dt->denali; | |
80 | + | |
81 | + denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg"); | |
82 | + nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data"); | |
83 | + if (!denali_reg || !nand_data) { | |
84 | + dev_err(&ofdev->dev, "resources not completely defined\n"); | |
85 | + return -EINVAL; | |
86 | + } | |
87 | + | |
88 | + denali->platform = DT; | |
89 | + denali->dev = &ofdev->dev; | |
90 | + denali->irq = platform_get_irq(ofdev, 0); | |
91 | + if (denali->irq < 0) { | |
92 | + dev_err(&ofdev->dev, "no irq defined\n"); | |
93 | + return -ENXIO; | |
94 | + } | |
95 | + | |
96 | + denali->flash_reg = request_and_map(&ofdev->dev, denali_reg); | |
97 | + if (!denali->flash_reg) | |
98 | + return -ENOMEM; | |
99 | + | |
100 | + denali->flash_mem = request_and_map(&ofdev->dev, nand_data); | |
101 | + if (!denali->flash_mem) | |
102 | + return -ENOMEM; | |
103 | + | |
104 | + if (!of_property_read_u32(ofdev->dev.of_node, | |
105 | + "dma-mask", (u32 *)&denali_dma_mask)) { | |
106 | + denali->dev->dma_mask = &denali_dma_mask; | |
107 | + } else { | |
108 | + denali->dev->dma_mask = NULL; | |
109 | + } | |
110 | + | |
111 | + dt->clk = clk_get(&ofdev->dev, NULL); | |
112 | + if (IS_ERR(dt->clk)) { | |
113 | + dev_err(&ofdev->dev, "no clk available\n"); | |
114 | + return PTR_ERR(dt->clk); | |
115 | + } | |
116 | + clk_prepare_enable(dt->clk); | |
117 | + | |
118 | + ret = denali_init(denali); | |
119 | + if (ret) | |
120 | + goto out_disable_clk; | |
121 | + | |
122 | + platform_set_drvdata(ofdev, dt); | |
123 | + return 0; | |
124 | + | |
125 | +out_disable_clk: | |
126 | + clk_disable_unprepare(dt->clk); | |
127 | + clk_put(dt->clk); | |
128 | + | |
129 | + return ret; | |
130 | +} | |
131 | + | |
132 | +static int __devexit denali_dt_remove(struct platform_device *ofdev) | |
133 | +{ | |
134 | + struct denali_dt *dt = platform_get_drvdata(ofdev); | |
135 | + | |
136 | + denali_remove(&dt->denali); | |
137 | + clk_disable(dt->clk); | |
138 | + clk_put(dt->clk); | |
139 | + | |
140 | + return 0; | |
141 | +} | |
142 | + | |
143 | +static struct platform_driver denali_dt_driver = { | |
144 | + .probe = denali_dt_probe, | |
145 | + .remove = __devexit_p(denali_dt_remove), | |
146 | + .driver = { | |
147 | + .name = "denali-nand-dt", | |
148 | + .owner = THIS_MODULE, | |
149 | + .of_match_table = of_match_ptr(denali_nand_dt_ids), | |
150 | + }, | |
151 | +}; | |
152 | + | |
153 | +static int __init denali_init_dt(void) | |
154 | +{ | |
155 | + return platform_driver_register(&denali_dt_driver); | |
156 | +} | |
157 | +module_init(denali_init_dt); | |
158 | + | |
159 | +static void __exit denali_exit_dt(void) | |
160 | +{ | |
161 | + platform_driver_unregister(&denali_dt_driver); | |
162 | +} | |
163 | +module_exit(denali_exit_dt); | |
164 | + | |
165 | +MODULE_LICENSE("GPL"); | |
166 | +MODULE_AUTHOR("Jamie Iles"); | |
167 | +MODULE_DESCRIPTION("DT driver for Denali NAND controller"); |