2 * Freescale UPM NAND driver.
4 * Copyright © 2007-2008 MontaVista Software, Inc.
6 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/delay.h>
17 #include <linux/mtd/nand.h>
18 #include <linux/mtd/nand_ecc.h>
19 #include <linux/mtd/partitions.h>
20 #include <linux/mtd/mtd.h>
21 #include <linux/of_platform.h>
22 #include <linux/of_gpio.h>
24 #include <asm/fsl_lbc.h>
29 struct nand_chip chip
;
31 #ifdef CONFIG_MTD_PARTITIONS
32 struct mtd_partition
*parts
;
36 uint8_t upm_addr_offset
;
37 uint8_t upm_cmd_offset
;
38 void __iomem
*io_base
;
43 #define to_fsl_upm_nand(mtd) container_of(mtd, struct fsl_upm_nand, mtd)
45 static int fun_chip_ready(struct mtd_info
*mtd
)
47 struct fsl_upm_nand
*fun
= to_fsl_upm_nand(mtd
);
49 if (gpio_get_value(fun
->rnb_gpio
))
52 dev_vdbg(fun
->dev
, "busy\n");
56 static void fun_wait_rnb(struct fsl_upm_nand
*fun
)
60 if (fun
->rnb_gpio
>= 0) {
61 while (--cnt
&& !fun_chip_ready(&fun
->mtd
))
64 dev_err(fun
->dev
, "tired waiting for RNB\n");
70 static void fun_cmd_ctrl(struct mtd_info
*mtd
, int cmd
, unsigned int ctrl
)
72 struct fsl_upm_nand
*fun
= to_fsl_upm_nand(mtd
);
74 if (!(ctrl
& fun
->last_ctrl
)) {
75 fsl_upm_end_pattern(&fun
->upm
);
77 if (cmd
== NAND_CMD_NONE
)
80 fun
->last_ctrl
= ctrl
& (NAND_ALE
| NAND_CLE
);
83 if (ctrl
& NAND_CTRL_CHANGE
) {
85 fsl_upm_start_pattern(&fun
->upm
, fun
->upm_addr_offset
);
86 else if (ctrl
& NAND_CLE
)
87 fsl_upm_start_pattern(&fun
->upm
, fun
->upm_cmd_offset
);
90 fsl_upm_run_pattern(&fun
->upm
, fun
->io_base
, cmd
);
95 static uint8_t fun_read_byte(struct mtd_info
*mtd
)
97 struct fsl_upm_nand
*fun
= to_fsl_upm_nand(mtd
);
99 return in_8(fun
->chip
.IO_ADDR_R
);
102 static void fun_read_buf(struct mtd_info
*mtd
, uint8_t *buf
, int len
)
104 struct fsl_upm_nand
*fun
= to_fsl_upm_nand(mtd
);
107 for (i
= 0; i
< len
; i
++)
108 buf
[i
] = in_8(fun
->chip
.IO_ADDR_R
);
111 static void fun_write_buf(struct mtd_info
*mtd
, const uint8_t *buf
, int len
)
113 struct fsl_upm_nand
*fun
= to_fsl_upm_nand(mtd
);
116 for (i
= 0; i
< len
; i
++) {
117 out_8(fun
->chip
.IO_ADDR_W
, buf
[i
]);
122 static int __devinit
fun_chip_init(struct fsl_upm_nand
*fun
,
123 const struct device_node
*upm_np
,
124 const struct resource
*io_res
)
127 struct device_node
*flash_np
;
128 #ifdef CONFIG_MTD_PARTITIONS
129 static const char *part_types
[] = { "cmdlinepart", NULL
, };
132 fun
->chip
.IO_ADDR_R
= fun
->io_base
;
133 fun
->chip
.IO_ADDR_W
= fun
->io_base
;
134 fun
->chip
.cmd_ctrl
= fun_cmd_ctrl
;
135 fun
->chip
.chip_delay
= fun
->chip_delay
;
136 fun
->chip
.read_byte
= fun_read_byte
;
137 fun
->chip
.read_buf
= fun_read_buf
;
138 fun
->chip
.write_buf
= fun_write_buf
;
139 fun
->chip
.ecc
.mode
= NAND_ECC_SOFT
;
141 if (fun
->rnb_gpio
>= 0)
142 fun
->chip
.dev_ready
= fun_chip_ready
;
144 fun
->mtd
.priv
= &fun
->chip
;
145 fun
->mtd
.owner
= THIS_MODULE
;
147 flash_np
= of_get_next_child(upm_np
, NULL
);
151 fun
->mtd
.name
= kasprintf(GFP_KERNEL
, "%x.%s", io_res
->start
,
153 if (!fun
->mtd
.name
) {
158 ret
= nand_scan(&fun
->mtd
, 1);
162 #ifdef CONFIG_MTD_PARTITIONS
163 ret
= parse_mtd_partitions(&fun
->mtd
, part_types
, &fun
->parts
, 0);
165 #ifdef CONFIG_MTD_OF_PARTS
167 ret
= of_mtd_parse_partitions(fun
->dev
, flash_np
, &fun
->parts
);
173 ret
= add_mtd_partitions(&fun
->mtd
, fun
->parts
, ret
);
176 ret
= add_mtd_device(&fun
->mtd
);
178 of_node_put(flash_np
);
182 static int __devinit
fun_probe(struct of_device
*ofdev
,
183 const struct of_device_id
*ofid
)
185 struct fsl_upm_nand
*fun
;
186 struct resource io_res
;
187 const uint32_t *prop
;
191 fun
= kzalloc(sizeof(*fun
), GFP_KERNEL
);
195 ret
= of_address_to_resource(ofdev
->node
, 0, &io_res
);
197 dev_err(&ofdev
->dev
, "can't get IO base\n");
201 ret
= fsl_upm_find(io_res
.start
, &fun
->upm
);
203 dev_err(&ofdev
->dev
, "can't find UPM\n");
207 prop
= of_get_property(ofdev
->node
, "fsl,upm-addr-offset", &size
);
208 if (!prop
|| size
!= sizeof(uint32_t)) {
209 dev_err(&ofdev
->dev
, "can't get UPM address offset\n");
213 fun
->upm_addr_offset
= *prop
;
215 prop
= of_get_property(ofdev
->node
, "fsl,upm-cmd-offset", &size
);
216 if (!prop
|| size
!= sizeof(uint32_t)) {
217 dev_err(&ofdev
->dev
, "can't get UPM command offset\n");
221 fun
->upm_cmd_offset
= *prop
;
223 fun
->rnb_gpio
= of_get_gpio(ofdev
->node
, 0);
224 if (fun
->rnb_gpio
>= 0) {
225 ret
= gpio_request(fun
->rnb_gpio
, dev_name(&ofdev
->dev
));
227 dev_err(&ofdev
->dev
, "can't request RNB gpio\n");
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");
236 prop
= of_get_property(ofdev
->node
, "chip-delay", NULL
);
238 fun
->chip_delay
= *prop
;
240 fun
->chip_delay
= 50;
242 fun
->io_base
= devm_ioremap_nocache(&ofdev
->dev
, io_res
.start
,
243 io_res
.end
- io_res
.start
+ 1);
249 fun
->dev
= &ofdev
->dev
;
250 fun
->last_ctrl
= NAND_CLE
;
252 ret
= fun_chip_init(fun
, ofdev
->node
, &io_res
);
256 dev_set_drvdata(&ofdev
->dev
, fun
);
260 if (fun
->rnb_gpio
>= 0)
261 gpio_free(fun
->rnb_gpio
);
268 static int __devexit
fun_remove(struct of_device
*ofdev
)
270 struct fsl_upm_nand
*fun
= dev_get_drvdata(&ofdev
->dev
);
272 nand_release(&fun
->mtd
);
273 kfree(fun
->mtd
.name
);
275 if (fun
->rnb_gpio
>= 0)
276 gpio_free(fun
->rnb_gpio
);
283 static struct of_device_id of_fun_match
[] = {
284 { .compatible
= "fsl,upm-nand" },
287 MODULE_DEVICE_TABLE(of
, of_fun_match
);
289 static struct of_platform_driver of_fun_driver
= {
290 .name
= "fsl,upm-nand",
291 .match_table
= of_fun_match
,
293 .remove
= __devexit_p(fun_remove
),
296 static int __init
fun_module_init(void)
298 return of_register_platform_driver(&of_fun_driver
);
300 module_init(fun_module_init
);
302 static void __exit
fun_module_exit(void)
304 of_unregister_platform_driver(&of_fun_driver
);
306 module_exit(fun_module_exit
);
308 MODULE_LICENSE("GPL");
309 MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
310 MODULE_DESCRIPTION("Driver for NAND chips working through Freescale "
311 "LocalBus User-Programmable Machine");