diff options
author | Felix Radensky <felix@embedded-sol.com> | 2011-04-26 05:36:46 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2011-05-24 21:01:14 -0400 |
commit | 410fe2f02630fa76b5311c06b7411731202d3b68 (patch) | |
tree | 211a7549bfb2115e7895765eede4c5471e450fe5 /drivers/mtd/nand | |
parent | 1ddd0d9a3177356f2a29c8f3826ad79e1ad18397 (diff) |
mtd: nand: ndfc: add multiple chip select support
This patch extends NDFC driver to support all 4 chip selects
available in NDFC NAND controller. Tested on custom 460EX board
with 2 chip select NAND device.
Artem: white-space cleanups
Signed-off-by: Felix Radensky <felix@embedded-sol.com>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/ndfc.c | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index bbe6d451290d..7ba65553d6ad 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/of_platform.h> | 33 | #include <linux/of_platform.h> |
34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
35 | 35 | ||
36 | #define NDFC_MAX_CS 4 | ||
36 | 37 | ||
37 | struct ndfc_controller { | 38 | struct ndfc_controller { |
38 | struct platform_device *ofdev; | 39 | struct platform_device *ofdev; |
@@ -46,12 +47,13 @@ struct ndfc_controller { | |||
46 | #endif | 47 | #endif |
47 | }; | 48 | }; |
48 | 49 | ||
49 | static struct ndfc_controller ndfc_ctrl; | 50 | static struct ndfc_controller ndfc_ctrl[NDFC_MAX_CS]; |
50 | 51 | ||
51 | static void ndfc_select_chip(struct mtd_info *mtd, int chip) | 52 | static void ndfc_select_chip(struct mtd_info *mtd, int chip) |
52 | { | 53 | { |
53 | uint32_t ccr; | 54 | uint32_t ccr; |
54 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 55 | struct nand_chip *nchip = mtd->priv; |
56 | struct ndfc_controller *ndfc = nchip->priv; | ||
55 | 57 | ||
56 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); | 58 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); |
57 | if (chip >= 0) { | 59 | if (chip >= 0) { |
@@ -64,7 +66,8 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip) | |||
64 | 66 | ||
65 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | 67 | static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
66 | { | 68 | { |
67 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 69 | struct nand_chip *chip = mtd->priv; |
70 | struct ndfc_controller *ndfc = chip->priv; | ||
68 | 71 | ||
69 | if (cmd == NAND_CMD_NONE) | 72 | if (cmd == NAND_CMD_NONE) |
70 | return; | 73 | return; |
@@ -77,7 +80,8 @@ static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl) | |||
77 | 80 | ||
78 | static int ndfc_ready(struct mtd_info *mtd) | 81 | static int ndfc_ready(struct mtd_info *mtd) |
79 | { | 82 | { |
80 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 83 | struct nand_chip *chip = mtd->priv; |
84 | struct ndfc_controller *ndfc = chip->priv; | ||
81 | 85 | ||
82 | return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; | 86 | return in_be32(ndfc->ndfcbase + NDFC_STAT) & NDFC_STAT_IS_READY; |
83 | } | 87 | } |
@@ -85,7 +89,8 @@ static int ndfc_ready(struct mtd_info *mtd) | |||
85 | static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) | 89 | static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) |
86 | { | 90 | { |
87 | uint32_t ccr; | 91 | uint32_t ccr; |
88 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 92 | struct nand_chip *chip = mtd->priv; |
93 | struct ndfc_controller *ndfc = chip->priv; | ||
89 | 94 | ||
90 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); | 95 | ccr = in_be32(ndfc->ndfcbase + NDFC_CCR); |
91 | ccr |= NDFC_CCR_RESET_ECC; | 96 | ccr |= NDFC_CCR_RESET_ECC; |
@@ -96,7 +101,8 @@ static void ndfc_enable_hwecc(struct mtd_info *mtd, int mode) | |||
96 | static int ndfc_calculate_ecc(struct mtd_info *mtd, | 101 | static int ndfc_calculate_ecc(struct mtd_info *mtd, |
97 | const u_char *dat, u_char *ecc_code) | 102 | const u_char *dat, u_char *ecc_code) |
98 | { | 103 | { |
99 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 104 | struct nand_chip *chip = mtd->priv; |
105 | struct ndfc_controller *ndfc = chip->priv; | ||
100 | uint32_t ecc; | 106 | uint32_t ecc; |
101 | uint8_t *p = (uint8_t *)&ecc; | 107 | uint8_t *p = (uint8_t *)&ecc; |
102 | 108 | ||
@@ -119,7 +125,8 @@ static int ndfc_calculate_ecc(struct mtd_info *mtd, | |||
119 | */ | 125 | */ |
120 | static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | 126 | static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
121 | { | 127 | { |
122 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 128 | struct nand_chip *chip = mtd->priv; |
129 | struct ndfc_controller *ndfc = chip->priv; | ||
123 | uint32_t *p = (uint32_t *) buf; | 130 | uint32_t *p = (uint32_t *) buf; |
124 | 131 | ||
125 | for(;len > 0; len -= 4) | 132 | for(;len > 0; len -= 4) |
@@ -128,7 +135,8 @@ static void ndfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) | |||
128 | 135 | ||
129 | static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 136 | static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
130 | { | 137 | { |
131 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 138 | struct nand_chip *chip = mtd->priv; |
139 | struct ndfc_controller *ndfc = chip->priv; | ||
132 | uint32_t *p = (uint32_t *) buf; | 140 | uint32_t *p = (uint32_t *) buf; |
133 | 141 | ||
134 | for(;len > 0; len -= 4) | 142 | for(;len > 0; len -= 4) |
@@ -137,7 +145,8 @@ static void ndfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | |||
137 | 145 | ||
138 | static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) | 146 | static int ndfc_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
139 | { | 147 | { |
140 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 148 | struct nand_chip *chip = mtd->priv; |
149 | struct ndfc_controller *ndfc = chip->priv; | ||
141 | uint32_t *p = (uint32_t *) buf; | 150 | uint32_t *p = (uint32_t *) buf; |
142 | 151 | ||
143 | for(;len > 0; len -= 4) | 152 | for(;len > 0; len -= 4) |
@@ -179,6 +188,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc, | |||
179 | chip->ecc.mode = NAND_ECC_HW; | 188 | chip->ecc.mode = NAND_ECC_HW; |
180 | chip->ecc.size = 256; | 189 | chip->ecc.size = 256; |
181 | chip->ecc.bytes = 3; | 190 | chip->ecc.bytes = 3; |
191 | chip->priv = ndfc; | ||
182 | 192 | ||
183 | ndfc->mtd.priv = chip; | 193 | ndfc->mtd.priv = chip; |
184 | ndfc->mtd.owner = THIS_MODULE; | 194 | ndfc->mtd.owner = THIS_MODULE; |
@@ -227,15 +237,10 @@ err: | |||
227 | 237 | ||
228 | static int __devinit ndfc_probe(struct platform_device *ofdev) | 238 | static int __devinit ndfc_probe(struct platform_device *ofdev) |
229 | { | 239 | { |
230 | struct ndfc_controller *ndfc = &ndfc_ctrl; | 240 | struct ndfc_controller *ndfc; |
231 | const __be32 *reg; | 241 | const __be32 *reg; |
232 | u32 ccr; | 242 | u32 ccr; |
233 | int err, len; | 243 | int err, len, cs; |
234 | |||
235 | spin_lock_init(&ndfc->ndfc_control.lock); | ||
236 | init_waitqueue_head(&ndfc->ndfc_control.wq); | ||
237 | ndfc->ofdev = ofdev; | ||
238 | dev_set_drvdata(&ofdev->dev, ndfc); | ||
239 | 244 | ||
240 | /* Read the reg property to get the chip select */ | 245 | /* Read the reg property to get the chip select */ |
241 | reg = of_get_property(ofdev->dev.of_node, "reg", &len); | 246 | reg = of_get_property(ofdev->dev.of_node, "reg", &len); |
@@ -243,7 +248,20 @@ static int __devinit ndfc_probe(struct platform_device *ofdev) | |||
243 | dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); | 248 | dev_err(&ofdev->dev, "unable read reg property (%d)\n", len); |
244 | return -ENOENT; | 249 | return -ENOENT; |
245 | } | 250 | } |
246 | ndfc->chip_select = be32_to_cpu(reg[0]); | 251 | |
252 | cs = be32_to_cpu(reg[0]); | ||
253 | if (cs >= NDFC_MAX_CS) { | ||
254 | dev_err(&ofdev->dev, "invalid CS number (%d)\n", cs); | ||
255 | return -EINVAL; | ||
256 | } | ||
257 | |||
258 | ndfc = &ndfc_ctrl[cs]; | ||
259 | ndfc->chip_select = cs; | ||
260 | |||
261 | spin_lock_init(&ndfc->ndfc_control.lock); | ||
262 | init_waitqueue_head(&ndfc->ndfc_control.wq); | ||
263 | ndfc->ofdev = ofdev; | ||
264 | dev_set_drvdata(&ofdev->dev, ndfc); | ||
247 | 265 | ||
248 | ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); | 266 | ndfc->ndfcbase = of_iomap(ofdev->dev.of_node, 0); |
249 | if (!ndfc->ndfcbase) { | 267 | if (!ndfc->ndfcbase) { |