aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorWolfgang Grandegger <wg@grandegger.com>2009-03-30 06:02:42 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-04-06 10:17:09 -0400
commitb6e0e8c07754c8aefd6ff3536463fed5f71405a0 (patch)
tree84233509d5ccf9efea3e92785c101ce3b051eaef /drivers
parentdb99a5523175ba15fef4719c722cea11b94911bb (diff)
[MTD] [NAND] FSL-UPM: add multi chip support
This patch adds support for multi-chip NAND devices to the FSL-UPM driver. This requires support for multiple GPIOs for the RNB pins. The NAND chips are selected through address lines defined by the FDT property "fsl,upm-addr-line-cs-offsets". Signed-off-by: Wolfgang Grandegger <wg@grandegger.com> Acked-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/nand/fsl_upm.c99
1 files changed, 76 insertions, 23 deletions
diff --git a/drivers/mtd/nand/fsl_upm.c b/drivers/mtd/nand/fsl_upm.c
index 7815a404a632..430de6de9ac6 100644
--- a/drivers/mtd/nand/fsl_upm.c
+++ b/drivers/mtd/nand/fsl_upm.c
@@ -36,7 +36,10 @@ struct fsl_upm_nand {
36 uint8_t upm_addr_offset; 36 uint8_t upm_addr_offset;
37 uint8_t upm_cmd_offset; 37 uint8_t upm_cmd_offset;
38 void __iomem *io_base; 38 void __iomem *io_base;
39 int rnb_gpio; 39 int rnb_gpio[NAND_MAX_CHIPS];
40 uint32_t mchip_offsets[NAND_MAX_CHIPS];
41 uint32_t mchip_count;
42 uint32_t mchip_number;
40 int chip_delay; 43 int chip_delay;
41}; 44};
42 45
@@ -46,7 +49,7 @@ static int fun_chip_ready(struct mtd_info *mtd)
46{ 49{
47 struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); 50 struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
48 51
49 if (gpio_get_value(fun->rnb_gpio)) 52 if (gpio_get_value(fun->rnb_gpio[fun->mchip_number]))
50 return 1; 53 return 1;
51 54
52 dev_vdbg(fun->dev, "busy\n"); 55 dev_vdbg(fun->dev, "busy\n");
@@ -55,9 +58,9 @@ static int fun_chip_ready(struct mtd_info *mtd)
55 58
56static void fun_wait_rnb(struct fsl_upm_nand *fun) 59static void fun_wait_rnb(struct fsl_upm_nand *fun)
57{ 60{
58 int cnt = 1000000; 61 if (fun->rnb_gpio[fun->mchip_number] >= 0) {
62 int cnt = 1000000;
59 63
60 if (fun->rnb_gpio >= 0) {
61 while (--cnt && !fun_chip_ready(&fun->mtd)) 64 while (--cnt && !fun_chip_ready(&fun->mtd))
62 cpu_relax(); 65 cpu_relax();
63 if (!cnt) 66 if (!cnt)
@@ -69,7 +72,9 @@ static void fun_wait_rnb(struct fsl_upm_nand *fun)
69 72
70static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) 73static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
71{ 74{
75 struct nand_chip *chip = mtd->priv;
72 struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); 76 struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
77 u32 mar;
73 78
74 if (!(ctrl & fun->last_ctrl)) { 79 if (!(ctrl & fun->last_ctrl)) {
75 fsl_upm_end_pattern(&fun->upm); 80 fsl_upm_end_pattern(&fun->upm);
@@ -87,11 +92,29 @@ static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
87 fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); 92 fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset);
88 } 93 }
89 94
90 fsl_upm_run_pattern(&fun->upm, fun->io_base, cmd); 95 mar = (cmd << (32 - fun->upm.width)) |
96 fun->mchip_offsets[fun->mchip_number];
97 fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar);
91 98
92 fun_wait_rnb(fun); 99 fun_wait_rnb(fun);
93} 100}
94 101
102static void fun_select_chip(struct mtd_info *mtd, int mchip_nr)
103{
104 struct nand_chip *chip = mtd->priv;
105 struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
106
107 if (mchip_nr == -1) {
108 chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE);
109 } else if (mchip_nr >= 0) {
110 fun->mchip_number = mchip_nr;
111 chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr];
112 chip->IO_ADDR_W = chip->IO_ADDR_R;
113 } else {
114 BUG();
115 }
116}
117
95static uint8_t fun_read_byte(struct mtd_info *mtd) 118static uint8_t fun_read_byte(struct mtd_info *mtd)
96{ 119{
97 struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); 120 struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd);
@@ -137,8 +160,10 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
137 fun->chip.read_buf = fun_read_buf; 160 fun->chip.read_buf = fun_read_buf;
138 fun->chip.write_buf = fun_write_buf; 161 fun->chip.write_buf = fun_write_buf;
139 fun->chip.ecc.mode = NAND_ECC_SOFT; 162 fun->chip.ecc.mode = NAND_ECC_SOFT;
163 if (fun->mchip_count > 1)
164 fun->chip.select_chip = fun_select_chip;
140 165
141 if (fun->rnb_gpio >= 0) 166 if (fun->rnb_gpio[0] >= 0)
142 fun->chip.dev_ready = fun_chip_ready; 167 fun->chip.dev_ready = fun_chip_ready;
143 168
144 fun->mtd.priv = &fun->chip; 169 fun->mtd.priv = &fun->chip;
@@ -155,7 +180,7 @@ static int __devinit fun_chip_init(struct fsl_upm_nand *fun,
155 goto err; 180 goto err;
156 } 181 }
157 182
158 ret = nand_scan(&fun->mtd, 1); 183 ret = nand_scan(&fun->mtd, fun->mchip_count);
159 if (ret) 184 if (ret)
160 goto err; 185 goto err;
161 186
@@ -185,8 +210,10 @@ static int __devinit fun_probe(struct of_device *ofdev,
185 struct fsl_upm_nand *fun; 210 struct fsl_upm_nand *fun;
186 struct resource io_res; 211 struct resource io_res;
187 const uint32_t *prop; 212 const uint32_t *prop;
213 int rnb_gpio;
188 int ret; 214 int ret;
189 int size; 215 int size;
216 int i;
190 217
191 fun = kzalloc(sizeof(*fun), GFP_KERNEL); 218 fun = kzalloc(sizeof(*fun), GFP_KERNEL);
192 if (!fun) 219 if (!fun)
@@ -208,7 +235,7 @@ static int __devinit fun_probe(struct of_device *ofdev,
208 if (!prop || size != sizeof(uint32_t)) { 235 if (!prop || size != sizeof(uint32_t)) {
209 dev_err(&ofdev->dev, "can't get UPM address offset\n"); 236 dev_err(&ofdev->dev, "can't get UPM address offset\n");
210 ret = -EINVAL; 237 ret = -EINVAL;
211 goto err2; 238 goto err1;
212 } 239 }
213 fun->upm_addr_offset = *prop; 240 fun->upm_addr_offset = *prop;
214 241
@@ -216,21 +243,40 @@ static int __devinit fun_probe(struct of_device *ofdev,
216 if (!prop || size != sizeof(uint32_t)) { 243 if (!prop || size != sizeof(uint32_t)) {
217 dev_err(&ofdev->dev, "can't get UPM command offset\n"); 244 dev_err(&ofdev->dev, "can't get UPM command offset\n");
218 ret = -EINVAL; 245 ret = -EINVAL;
219 goto err2; 246 goto err1;
220 } 247 }
221 fun->upm_cmd_offset = *prop; 248 fun->upm_cmd_offset = *prop;
222 249
223 fun->rnb_gpio = of_get_gpio(ofdev->node, 0); 250 prop = of_get_property(ofdev->node,
224 if (fun->rnb_gpio >= 0) { 251 "fsl,upm-addr-line-cs-offsets", &size);
225 ret = gpio_request(fun->rnb_gpio, dev_name(&ofdev->dev)); 252 if (prop && (size / sizeof(uint32_t)) > 0) {
226 if (ret) { 253 fun->mchip_count = size / sizeof(uint32_t);
227 dev_err(&ofdev->dev, "can't request RNB gpio\n"); 254 if (fun->mchip_count >= NAND_MAX_CHIPS) {
255 dev_err(&ofdev->dev, "too much multiple chips\n");
256 goto err1;
257 }
258 for (i = 0; i < fun->mchip_count; i++)
259 fun->mchip_offsets[i] = prop[i];
260 } else {
261 fun->mchip_count = 1;
262 }
263
264 for (i = 0; i < fun->mchip_count; i++) {
265 fun->rnb_gpio[i] = -1;
266 rnb_gpio = of_get_gpio(ofdev->node, i);
267 if (rnb_gpio >= 0) {
268 ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev));
269 if (ret) {
270 dev_err(&ofdev->dev,
271 "can't request RNB gpio #%d\n", i);
272 goto err2;
273 }
274 gpio_direction_input(rnb_gpio);
275 fun->rnb_gpio[i] = rnb_gpio;
276 } else if (rnb_gpio == -EINVAL) {
277 dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i);
228 goto err2; 278 goto err2;
229 } 279 }
230 gpio_direction_input(fun->rnb_gpio);
231 } else if (fun->rnb_gpio == -EINVAL) {
232 dev_err(&ofdev->dev, "specified RNB gpio is invalid\n");
233 goto err2;
234 } 280 }
235 281
236 prop = of_get_property(ofdev->node, "chip-delay", NULL); 282 prop = of_get_property(ofdev->node, "chip-delay", NULL);
@@ -240,7 +286,7 @@ static int __devinit fun_probe(struct of_device *ofdev,
240 fun->chip_delay = 50; 286 fun->chip_delay = 50;
241 287
242 fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, 288 fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start,
243 io_res.end - io_res.start + 1); 289 io_res.end - io_res.start + 1);
244 if (!fun->io_base) { 290 if (!fun->io_base) {
245 ret = -ENOMEM; 291 ret = -ENOMEM;
246 goto err2; 292 goto err2;
@@ -257,8 +303,11 @@ static int __devinit fun_probe(struct of_device *ofdev,
257 303
258 return 0; 304 return 0;
259err2: 305err2:
260 if (fun->rnb_gpio >= 0) 306 for (i = 0; i < fun->mchip_count; i++) {
261 gpio_free(fun->rnb_gpio); 307 if (fun->rnb_gpio[i] < 0)
308 break;
309 gpio_free(fun->rnb_gpio[i]);
310 }
262err1: 311err1:
263 kfree(fun); 312 kfree(fun);
264 313
@@ -268,12 +317,16 @@ err1:
268static int __devexit fun_remove(struct of_device *ofdev) 317static int __devexit fun_remove(struct of_device *ofdev)
269{ 318{
270 struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); 319 struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev);
320 int i;
271 321
272 nand_release(&fun->mtd); 322 nand_release(&fun->mtd);
273 kfree(fun->mtd.name); 323 kfree(fun->mtd.name);
274 324
275 if (fun->rnb_gpio >= 0) 325 for (i = 0; i < fun->mchip_count; i++) {
276 gpio_free(fun->rnb_gpio); 326 if (fun->rnb_gpio[i] < 0)
327 break;
328 gpio_free(fun->rnb_gpio[i]);
329 }
277 330
278 kfree(fun); 331 kfree(fun);
279 332