一、一个简单的nand_flash驱动
1.定义nand_chip、mtd_info两个结构体
如上图所示:
nand_chip 结构体:是给nand_scan函数用的,而nand_scan函数提供了选中nand、发出命令、发出地址、发出数据、读取数据、判断状态等功能,所以nand_chip结构体上必须定义一系列实现上面功能能的函数,包括选中函数,负责发地址与命令的函数,以及判断状态的函数,最重要的就是io读取的虚拟地址。
mtd_info结构体:MTD(Memory Technology Device)即内存技术设在linux内核中,引入mtd层为NOR Flash和NAND Flash设备提供统一的接口,将文件系统于底层Flash存储设备进行了隔离。
MTD设备可以分为四层,从上到下依次为:设备节点层,MTD设备层,MTD原始设备层,Flash硬件驱动层。
Flash硬件驱动层:负责对Flash硬件的读、写和擦除操作。MTD设备的NAND flash芯片的驱动在drivers/mtd/nand目录下,nor flash芯片驱动位于drivers/mtd/chips目录下。
MTD原始设备层:用于描述MTD原始设备的数据结构体是mtd_info ,它定义了大量的关于MTD的数据和操作函数,其中mtdcore.c:实现原始设备接口的相关实现,mtdpart.c:实现mtd分区接口相关实现。
MTD设备层: 基于MTD原始设备,linux系统可以定义出MTD的块设备(主设备号31)和字符设备(设备号90),其中mtdchar.c实现mtd字符设备接口相关实现,mtdblock.c用于实现块设备接口相关实现。
设备节点层:通过mknode在/dev子目录下建立MTD块设备节点,通过此设备节点即可访问MTD字符设备和块设备。
2.在init函数中初始化结构体
1 static int lhy_nand_init(void){
2
3 /* 1.分配一个nand_chip结构体 */
4 lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
5 /* 2.设置 */
6 /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用
7 * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能
8 */
9 lhy_nand->select_chip = lhy_select_chip; //选中,芯片选择函数
10 lhy_nand->cmd_ctrl = lhy_nand_cmd_ctrl; //负责发送地址,命令
11 lhy_nand->IO_ADDR_R = "NFDATA 的虚拟地址";
12 lhy_nand->IO_ADDR_R = "NFDATA 的虚拟地址";
13 lhy_nand->dev_ready = lhy_dev_ready;
14 /* 3.硬件相关的操作 */
15
16 /* 4.使用nand_scan */
17 lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
18 lhy_mtd->priv = lhy_nand; //私有数据为我们的nand_chip结构体
19 lhy_mtd->owner = THIS_MODULE;
20
21 nand_scan(lhy_mtd,1); //扫描识别nand flash,并且构造mtd,最大芯片个数为1
22 /* 5.add_mtd_partitions */
23
24
25 return 0;
26 }
3.实现上述方法:
1 /* 芯片选择 */
2 static void lhy_select_chip(struct mtd_info *mtd,int chipnr)
3 {
4 if(chipnr == -1){
5 /* 取消选中,NFCONT[1]设为0 */
6 }else{
7 /* 选中:NFCONT[1]设为1 */
8 }
9 }
10 //发送命令,地址,数据
11 static void lhy_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
12 {
13 if (ctrl & NAND_CLE){
14 /* 发命令 : NFCMMD=dat*/
15 writeb(cmd, host->io_base + (1 << host->board->cle));
16 }else{
17 writeb(cmd, host->io_base + (1 << host->board->ale));
18 }
19 }
20 //判断状态
21 static int lhy_dev_ready(struct mtd_info *mtd)
22 {
23 return "NFSTAT 的 bit[0]";
24 }
附上驱动程序nand_flash1:
1 /*
2 * 参考:linux-2.6.31driversmtdnands3c2410.c atmel_nand.c
3 */
4
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
13 #include
14 #include
15 #include
16
17 static struct nand_chip *lhy_nand;
18 static struct mtd_info *lhy_mtd; //定义一个mtd_info结构体
19
20 /* 芯片选择 */
21 static void lhy_select_chip(struct mtd_info *mtd,int chipnr)
22 {
23 if(chipnr == -1){
24 /* 取消选中,NFCONT[1]设为0 */
25 }else{
26 /* 选中:NFCONT[1]设为1 */
27 }
28 }
29 //发送命令,地址,数据
30 static void lhy_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
31 {
32 if (ctrl & NAND_CLE){
33 /* 发命令 : NFCMMD=dat*/
34 writeb(cmd, host->io_base + (1 << host->board->cle));
35 }else{
36 writeb(cmd, host->io_base + (1 << host->board->ale));
37 }
38 }
39 //判断状态
40 static int lhy_dev_ready(struct mtd_info *mtd)
41 {
42 return "NFSTAT 的 bit[0]";
43 }
44
45 static int lhy_nand_init(void){
46
47 /* 1.分配一个nand_chip结构体 */
48 lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
49 /* 2.设置 */
50 /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用
51 * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能
52 */
53 lhy_nand->select_chip = lhy_select_chip; //选中,芯片选择函数
54 lhy_nand->cmd_ctrl = lhy_nand_cmd_ctrl; //负责发送地址,命令
55 lhy_nand->IO_ADDR_R = "NFDATA 的虚拟地址";
56 lhy_nand->IO_ADDR_R = "NFDATA 的虚拟地址";
57 lhy_nand->dev_ready = lhy_dev_ready;
58 /* 3.硬件相关的操作 */
59
60 /* 4.使用nand_scan */
61 lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
62 lhy_mtd->priv = lhy_nand; //私有数据为我们的nand_chip结构体
63 lhy_mtd->owner = THIS_MODULE;
64
65 nand_scan(lhy_mtd,1); //扫描识别nand flash,并且构造mtd,最大芯片个数为1
66 /* 5.add_mtd_partitions */
67
68
69 return 0;
70 }
71
72 static void lhy_nand_exit(void){
73 if(lhy_nand)
74 kfree(lhy_nand);
75 if(lhy_mtd)
76 kfree(lhy_mtd);
77 }
78
79 module_init(lhy_nand_init);
80 module_exit(lhy_nand_exit);
81 MODULE_LICENSE("GPL");
82
83
84 /*
85 S3C2440 U-BOOT 的NAND操作
86
87 1.读取ID
88 选中 NFCONT的bit1设为0 md.1 0x4E000004 1; mw.1 0x4e000004 1
89 发出命令0x90 NFCMMD=0X90 mw.b 0x4E000008 0x90
90 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00
91 读出数据得到0XEC val=NFDATA md.b 0x4E000010 1
92 读数据得到device code val=NFDATA md.b 0x4E000010 1
93 退出读ID状态 NFCMMD=0xff mw.b 0x4E000008 0xff
94
95 2.读内容 读0地址的数据
96 输入命令: nand dump 0 得到nand
97
98 选中 NFCONT的bit1设为0 md.1 0x4E000004 1; mw.1 0x4e000004 1
99 发出命令0x00 NFCMMD=0X00 mw.b 0x4E000008 0x00
100
101 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00
102 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00
103 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00
104 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00
105 发出地址0x00 NFADD=0X00 mw.b 0x4E00000c 0x00
106
107 发出命令0x30 NFCMMD=0X00 mw.b 0x4E000008 0x30
108
109 //接下来就是从0地址开始一个字节一个字节的读出数据,和前面nand dump 0 的数据一样
110 读出数据得到0x17 val=NFDATA md.b 0x4E000010 1
111 读出数据得到0x00 val=NFDATA md.b 0x4E000010 1
112 读出数据得到0x00 val=NFDATA md.b 0x4E000010 1
113
114 退出读状态 NFCMMD=0xff mw.b 0x4E000008 0xff
115
116 3.NAND flash 驱动层次 Atmel_nand.c Mtdchar.c
117 块设备: 知道怎么优化
118 NAND Flash协议:知道发什么来读写,擦除,识别
119 硬件相关: 知道怎样发命令/地址,读写数据
120
121 硬件相关:
122 ①分配nand_chip 结构体
123 ②设置nand_chip
124 ③硬件相关设备
125 ④使用 nand_scan / add_mtd_partitions
126
127 */
二、完善前面的程序