[Linux]nand驱动程序
[Linux]nand驱动程序
艾恩凝
2021/7/2
introuction
nand flash 算是块设备,一般设备分为字符设备和块设备,块设备不同于字符设备,个人看来最大的区别就是块设备为了提高性能,不能可读可写任意切换,块设备就是对这个进行优化,使速度更加快速。
nand flash驱动 主要是控制2440芯片,下图硬件相关那,程序本身不重要,最主要的是理解内核对nand flash驱动的支持
nand flash framework
code
1#include <linux/module.h>
2#include <linux/types.h>
3#include <linux/init.h>
4#include <linux/kernel.h>
5#include <linux/string.h>
6#include <linux/ioport.h>
7#include <linux/platform_device.h>
8#include <linux/delay.h>
9#include <linux/err.h>
10#include <linux/slab.h>
11#include <linux/clk.h>
12
13#include <linux/mtd/mtd.h>
14#include <linux/mtd/nand.h>
15#include <linux/mtd/nand_ecc.h>
16#include <linux/mtd/partitions.h>
17
18#include <asm/io.h>
19
20#include <asm/arch/regs-nand.h>
21#include <asm/arch/nand.h>
22
23struct s3c_nand_regs {
24 unsigned long nfconf ;
25 unsigned long nfcont ;
26 unsigned long nfcmd ;
27 unsigned long nfaddr ;
28 unsigned long nfdata ;
29 unsigned long nfeccd0 ;
30 unsigned long nfeccd1 ;
31 unsigned long nfeccd ;
32 unsigned long nfstat ;
33 unsigned long nfestat0;
34 unsigned long nfestat1;
35 unsigned long nfmecc0 ;
36 unsigned long nfmecc1 ;
37 unsigned long nfsecc ;
38 unsigned long nfsblk ;
39 unsigned long nfeblk ;
40 };
41
42static struct nand_chip *s3c_nand;
43static struct mtd_info *s3c_mtd;
44static struct s3c_nand_regs *s3c_nand_regs;
45static struct mtd_partition s3c_nand_parts[] = {
46 [0] = {
47 .name = "bootloader",
48 .size = 0x00040000,
49 .offset = 0,
50 },
51 [1] = {
52 .name = "params",
53 .offset = MTDPART_OFS_APPEND,
54 .size = 0x00020000,
55 },
56 [2] = {
57 .name = "kernel",
58 .offset = MTDPART_OFS_APPEND,
59 .size = 0x00200000,
60 },
61 [3] = {
62 .name = "root",
63 .offset = MTDPART_OFS_APPEND,
64 .size = MTDPART_SIZ_FULL,
65 }
66};
67
68static void s3c2440_select_chip(struct mtd_info *mtd, int chipnr)
69{
70 if (chipnr == -1)
71 {
72 /* 取消选中: NFCONT[1]设为0 */
73 s3c_nand_regs->nfcont |= (1<<1);
74 }
75 else
76 {
77 /* 选中: NFCONT[1]设为1 */
78 s3c_nand_regs->nfcont &= ~(1<<1);
79
80 }
81}
82
83static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
84{
85 if (ctrl & NAND_CLE)
86 {
87 /* 发命令: NFCMMD=dat */
88 s3c_nand_regs->nfcmd = dat;
89 }
90 else
91 {
92 /* 发地址: NFADDR=dat */
93 s3c_nand_regs->nfaddr = dat;
94 }
95}
96
97static int s3c2440_dev_ready(struct mtd_info *mtd)
98{
99 return (s3c_nand_regs->nfstat & (1<<0));
100}
101
102
103static int s3c_nand_init(void)
104{
105 struct clk *clk;
106
107 /* 1. 分配一个nand_chip结构体 */
108 s3c_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
109
110 s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs));
111 /* 2. 设置nand_chip */
112 /* 设置nand_chip是给nand_scan函数使用的, 如果不知道怎么设置, 先看nand_scan怎么使用
113 * 它应该提供:选中,发命令,发地址,发数据,读数据,判断状态的功能
114 */
115 s3c_nand->select_chip = s3c2440_select_chip;
116 s3c_nand->cmd_ctrl = s3c2440_cmd_ctrl;
117 s3c_nand->IO_ADDR_R = &s3c_nand_regs->nfdata;
118 s3c_nand->IO_ADDR_W = &s3c_nand_regs->nfdata;
119 s3c_nand->dev_ready = s3c2440_dev_ready;
120 s3c_nand->ecc.mode = NAND_ECC_SOFT;//ecc
121
122 /* 3. 硬件相关的设置: 根据NAND FLASH的手册设置时间参数 */
123 /* 使能NAND FLASH控制器的时钟 */
124 clk = clk_get(NULL, "nand");
125 clk_enable(clk); /* CLKCON'bit[4] */
126
127 /* HCLK=100MHz
128 * TACLS: 发出CLE/ALE之后多长时间才发出nWE信号, 从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
129 * TWRPH0: nWE的脉冲宽度, HCLK x ( TWRPH0 + 1 ), 从NAND手册可知它要>=12ns, 所以TWRPH0>=1
130 * TWRPH1: nWE变为高电平后多长时间CLE/ALE才能变为低电平, 从NAND手册可知它要>=5ns, 所以TWRPH1>=0
131 */
132#define TACLS 0
133#define TWRPH0 1
134#define TWRPH1 0
135 s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
136
137 /* NFCONT:
138 * BIT1-设为1, 取消片选
139 * BIT0-设为1, 使能NAND FLASH控制器
140 */
141 s3c_nand_regs->nfcont = (1<<1) | (1<<0);
142
143 /* 4. 使用: nand_scan */
144 s3c_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
145 s3c_mtd->owner = THIS_MODULE;
146 s3c_mtd->priv = s3c_nand;
147
148 nand_scan(s3c_mtd, 1); /* 识别NAND FLASH, 构造mtd_info */
149
150 /* 5. add_mtd_partitions */
151 add_mtd_partitions(s3c_mtd, s3c_nand_parts, 4);
152 return 0;
153}
154
155static void s3c_nand_exit(void)
156{
157 del_mtd_partitions(s3c_mtd);
158 kfree(s3c_mtd);
159 iounmap(s3c_nand_regs);
160 kfree(s3c_nand);
161}
162
163module_init(s3c_nand_init);
164module_exit(s3c_nand_exit);
165
166MODULE_AUTHOR("https://aeneag.xyz");
167MODULE_VERSION("0.1");
168MODULE_DESCRIPTION("S3C2440 Mouse Driver");
169MODULE_LICENSE("GPL");
end
艾恩凝
写于大连
2021年7月2日
catalogue
[Linux]驱动系列目录
吾心信其可行,
则移山填海之难,
终有成功之日!
——孙文
则移山填海之难,
终有成功之日!
——孙文
评论
0 评论