S3C2440 nand_flash驱动程序

20150418 S3C2440 nand_flash驱动程序

2015-04-18 Lover雪儿

一、一个简单的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.31\drivers\mtd\nand\s3c2410.c   atmel_nand.c
  3  */
  4
  5 #include <linux/slab.h>
  6 #include <linux/module.h>
  7 #include <linux/moduleparam.h>
  8 #include <linux/platform_device.h>
  9 #include <linux/mtd/mtd.h>
 10 #include <linux/mtd/nand.h>
 11 #include <linux/mtd/partitions.h>
 12 #include <linux/clk.h>
 13 #include <linux/io.h>
 14 #include <mach/board.h>
 15 #include <mach/cpu.h>
 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 */

nandflash1.c

二、完善前面的程序

1.定义芯片的内存地址,由于其地址是互相相连的所以我们可以使用结构体来省事。

//寄存器结构体
struct lhy_nand_regs{
    unsigned long NFCONF   ; //偏移地址: S3C2410_NFREG(0x00)
    unsigned long NFCONT   ; //偏移地址: S3C2410_NFREG(0x04)
    unsigned long NFCMD    ; //偏移地址: S3C2410_NFREG(0x08)
    unsigned long NFADDR   ; //偏移地址: S3C2410_NFREG(0x0C)
    unsigned long NFDATA   ; //偏移地址: S3C2410_NFREG(0x10)
    unsigned long NFECCD0  ; //偏移地址: S3C2410_NFREG(0x14)
    unsigned long NFECCD1  ; //偏移地址: S3C2410_NFREG(0x18)
    unsigned long NFECCD   ; //偏移地址: S3C2410_NFREG(0x1C)
    unsigned long NFSTAT   ; //偏移地址: S3C2410_NFREG(0x20)
    unsigned long NFESTAT0 ; //偏移地址: S3C2410_NFREG(0x24)
    unsigned long NFESTAT1 ; //偏移地址: S3C2410_NFREG(0x28)
    unsigned long NFMECC0  ; //偏移地址: S3C2410_NFREG(0x2C)
    unsigned long NFMECC1  ; //偏移地址: S3C2410_NFREG(0x30)
    unsigned long NFSECC   ; //偏移地址: S3C2410_NFREG(0x34)
    unsigned long NFSBLK   ; //偏移地址: S3C2410_NFREG(0x38)
    unsigned long NFEBLK   ; //偏移地址: S3C2410_NFREG(0x3C)
};

2.映射寄存器地址内存并其配置

static int lhy_nand_init(void){

    /* 1.分配一个nand_chip结构体 */
    lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);

    lhy_nand_regs = ioremap(0x4E000000,sizeof(struct lhy_nand_regs)); //映射寄存器
    /* 2.设置 */
    /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用
     *         它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能
     */
    lhy_nand->select_chip = lhy_select_chip;          //选中,芯片选择函数
    lhy_nand->cmd_ctrl       = lhy_nand_cmd_ctrl;        //负责发送地址,命令
    lhy_nand->IO_ADDR_R   = lhy_nand_regs->NFDATA;    //读寄存器
    lhy_nand->IO_ADDR_W   = lhy_nand_regs->NFDATA;    //写寄存器
    lhy_nand->dev_ready      = lhy_dev_ready;            //判断状态
    /* 3.硬件相关的操作 根据nand flash的手册设置时间参数
     * HCLK = 100MHz
     * TACLS: 发出CLE/ALE之后多长时间发出nWE信号,从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
     * TWRPH0: nWE的信号的脉冲宽度,HCLK *(TWPRH0 + 1),从NAND手册可知它要>=12ns,所以TWRPH0>=1
     * TWRPH1:表示nWE信号变为高电平后,CLE/ALE多长时间才能变为低电平,从手册可知他要>=5ns,所以TWRPH1>=0
     */
#define TACLS     0
#define TWRPH0    1
#define TWRPH1    0
    lhy_nand_regs->NFCONF |= (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);

    /* NFCONT的bit1设为1,表示片 选 */
    lhy_nand_regs->NFCONT =  (1<<1) | (1<<0);
    /* 4.使用nand_scan */
    lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
    lhy_mtd->priv = lhy_nand;            //私有数据为我们的nand_chip结构体
    lhy_mtd->owner = THIS_MODULE;

    nand_scan(lhy_mtd,1);        //扫描识别nand flash,并且构造mtd,最大芯片个数为1
    /* 5.add_mtd_partitions */

    return 0;
}

附上驱动程序nand_flash2:

  1 /*
  2  * 参考:linux-2.6.31\drivers\mtd\nand\s3c2410.c   atmel_nand.c
  3  */
  4
  5 #include <linux/slab.h>
  6 #include <linux/module.h>
  7 #include <linux/moduleparam.h>
  8 #include <linux/platform_device.h>
  9 #include <linux/mtd/mtd.h>
 10 #include <linux/mtd/nand.h>
 11 #include <linux/mtd/partitions.h>
 12 #include <linux/clk.h>
 13 #include <linux/io.h>
 14 #include <mach/board.h>
 15 #include <mach/cpu.h>
 16
 17 //寄存器结构体
 18 struct lhy_nand_regs{
 19     unsigned long NFCONF   ; //偏移地址: S3C2410_NFREG(0x00)
 20     unsigned long NFCONT   ; //偏移地址: S3C2410_NFREG(0x04)
 21     unsigned long NFCMD    ; //偏移地址: S3C2410_NFREG(0x08)
 22     unsigned long NFADDR   ; //偏移地址: S3C2410_NFREG(0x0C)
 23     unsigned long NFDATA   ; //偏移地址: S3C2410_NFREG(0x10)
 24     unsigned long NFECCD0  ; //偏移地址: S3C2410_NFREG(0x14)
 25     unsigned long NFECCD1  ; //偏移地址: S3C2410_NFREG(0x18)
 26     unsigned long NFECCD   ; //偏移地址: S3C2410_NFREG(0x1C)
 27     unsigned long NFSTAT   ; //偏移地址: S3C2410_NFREG(0x20)
 28     unsigned long NFESTAT0 ; //偏移地址: S3C2410_NFREG(0x24)
 29     unsigned long NFESTAT1 ; //偏移地址: S3C2410_NFREG(0x28)
 30     unsigned long NFMECC0  ; //偏移地址: S3C2410_NFREG(0x2C)
 31     unsigned long NFMECC1  ; //偏移地址: S3C2410_NFREG(0x30)
 32     unsigned long NFSECC   ; //偏移地址: S3C2410_NFREG(0x34)
 33     unsigned long NFSBLK   ; //偏移地址: S3C2410_NFREG(0x38)
 34     unsigned long NFEBLK   ; //偏移地址: S3C2410_NFREG(0x3C)
 35 };
 36
 37 static struct nand_chip *lhy_nand;
 38 static struct mtd_info *lhy_mtd;            //定义一个mtd_info结构体
 39 static struct lhy_nand_regs *lhy_nand_res;    //定义寄存器的结构体指针
 40
 41 /* 芯片选择 */
 42 static void lhy_select_chip(struct mtd_info *mtd,int chipnr)
 43 {
 44     if(chipnr == -1){
 45         /* 取消选中,NFCONT[1]设为0 */
 46         lhy_nand_regs->NFCONT |= (1<<1);
 47     }else{
 48         /* 选中:NFCONT[1]设为1 */
 49     lhy_nand_regs->NFCONT &= ~(1<<1);
 50     }
 51 }
 52 //发送命令,地址,数据
 53 static void lhy_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 54 {
 55     if (ctrl & NAND_CLE){
 56         /* 发命令 : NFCMMD=dat*/
 57         lhy_nand_regs->NFCMD = cmd;
 58     }else{
 59         writeb(cmd, host->io_base + (1 << host->board->ale));
 60         lhy_nand_regs->NFADDR = cmd;
 61     }
 62 }
 63 //判断状态
 64 static int lhy_dev_ready(struct mtd_info *mtd)
 65 {
 66     return (lhy_nand_regs->NFSTAT & (1<<0));
 67 }
 68
 69 static int lhy_nand_init(void){
 70
 71     /* 1.分配一个nand_chip结构体 */
 72     lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
 73
 74     lhy_nand_regs = ioremap(0x4E000000,sizeof(struct lhy_nand_regs)); //映射寄存器
 75     /* 2.设置 */
 76     /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用
 77      *         它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能
 78      */
 79     lhy_nand->select_chip = lhy_select_chip;          //选中,芯片选择函数
 80     lhy_nand->cmd_ctrl       = lhy_nand_cmd_ctrl;        //负责发送地址,命令
 81     lhy_nand->IO_ADDR_R   = lhy_nand_regs->NFDATA;    //读寄存器
 82     lhy_nand->IO_ADDR_W   = lhy_nand_regs->NFDATA;    //写寄存器
 83     lhy_nand->dev_ready      = lhy_dev_ready;            //判断状态
 84     /* 3.硬件相关的操作 根据nand flash的手册设置时间参数
 85      * HCLK = 100MHz
 86      * TACLS: 发出CLE/ALE之后多长时间发出nWE信号,从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
 87      * TWRPH0: nWE的信号的脉冲宽度,HCLK *(TWPRH0 + 1),从NAND手册可知它要>=12ns,所以TWRPH0>=1
 88      * TWRPH1:表示nWE信号变为高电平后,CLE/ALE多长时间才能变为低电平,从手册可知他要>=5ns,所以TWRPH1>=0
 89      */
 90 #define TACLS     0
 91 #define TWRPH0    1
 92 #define TWRPH1    0
 93     lhy_nand_regs->NFCONF |= (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
 94
 95     /* NFCONT的bit1设为1,表示片 选 */
 96     lhy_nand_regs->NFCONT =  (1<<1) | (1<<0);
 97     /* 4.使用nand_scan */
 98     lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
 99     lhy_mtd->priv = lhy_nand;            //私有数据为我们的nand_chip结构体
100     lhy_mtd->owner = THIS_MODULE;
101
102     nand_scan(lhy_mtd,1);        //扫描识别nand flash,并且构造mtd,最大芯片个数为1
103     /* 5.add_mtd_partitions */
104
105     return 0;
106 }
107
108 static void lhy_nand_exit(void){
109     if(lhy_nand)
110         kfree(lhy_nand);
111     if(lhy_mtd)
112         kfree(lhy_mtd);
113     if(lhy_nand_regs)
114         iounmap(lhy_nand_regs);
115 }
116
117 module_init(lhy_nand_init);
118 module_exit(lhy_nand_exit);
119 MODULE_LICENSE("GPL");
120
121
122 /*
123 S3C2440 U-BOOT 的NAND操作
124
125 1.读取ID
126 选中                    NFCONT的bit1设为0    md.1 0x4E000004 1;    mw.1 0x4e000004 1
127 发出命令0x90            NFCMMD=0X90            mw.b 0x4E000008 0x90
128 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
129 读出数据得到0XEC          val=NFDATA            md.b 0x4E000010 1
130 读数据得到device code    val=NFDATA             md.b 0x4E000010 1
131 退出读ID状态            NFCMMD=0xff            mw.b 0x4E000008 0xff
132
133 2.读内容 读0地址的数据
134 输入命令: nand dump 0  得到nand
135
136 选中                    NFCONT的bit1设为0    md.1 0x4E000004 1;    mw.1 0x4e000004 1
137 发出命令0x00            NFCMMD=0X00            mw.b 0x4E000008 0x00
138
139 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
140 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
141 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
142 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
143 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
144
145 发出命令0x30            NFCMMD=0X00            mw.b 0x4E000008 0x30
146
147 //接下来就是从0地址开始一个字节一个字节的读出数据,和前面nand dump 0 的数据一样
148 读出数据得到0x17          val=NFDATA            md.b 0x4E000010 1
149 读出数据得到0x00          val=NFDATA            md.b 0x4E000010 1
150 读出数据得到0x00          val=NFDATA            md.b 0x4E000010 1
151
152 退出读状态                NFCMMD=0xff            mw.b 0x4E000008 0xff
153
154 3.NAND  flash 驱动层次  Atmel_nand.c  Mtdchar.c
155 块设备:        知道怎么优化
156 NAND Flash协议:知道发什么来读写,擦除,识别
157 硬件相关:        知道怎样发命令/地址,读写数据
158
159 硬件相关:
160 ①分配nand_chip 结构体
161 ②设置nand_chip
162 ③硬件相关设备
163 ④使用 nand_scan / add_mtd_partitions
164
165
166 */

nandflash2.c

三、增加ECC校验码

前面的程序是可以直接用的,但是加载驱动时会报ECC校验错误。

在flash设备中,每一页都有64b是不参与编址的,这一块是不参与统一编址OBB(out of bank)。

原因:nand flash内存中,数据很容易发生位反转,为了防止数据发生错误,引入了ECC校验。

解决方案:写一页数据时,这一页的数据生成ECC校验码,然后把ECC校验码写入OBB中。

读取数据时:首先读取page,读OOB里的ECC,根据page的内容实时计算ECC,看是否与OOB中的

ECC相同,若是相同则说明数据没有错误,否则通过ECC校验码也可以算出是哪一位发生错误。

实现方法:可以设置为软件实现或者硬件实现,只要在nand_chip中的ECC结构体的mode中设置为NAND_ECC_SOFT,就是开启了软件ECC校验。

nand_chip->ecc.mode = NAND_ECC_SOFT;            /*使能ECC校验码 enable ECC */

附上驱动程序nand_flash3.c

  1 /*
  2  * 参考:linux-2.6.31\drivers\mtd\nand\s3c2410.c   atmel_nand.c
  3  */
  4
  5 #include <linux/slab.h>
  6 #include <linux/module.h>
  7 #include <linux/moduleparam.h>
  8 #include <linux/platform_device.h>
  9 #include <linux/mtd/mtd.h>
 10 #include <linux/mtd/nand.h>
 11 #include <linux/mtd/partitions.h>
 12 #include <linux/clk.h>
 13 #include <linux/io.h>
 14 #include <mach/board.h>
 15 #include <mach/cpu.h>
 16
 17 //寄存器结构体
 18 struct lhy_nand_regs{
 19     unsigned long NFCONF   ; //偏移地址: S3C2410_NFREG(0x00)
 20     unsigned long NFCONT   ; //偏移地址: S3C2410_NFREG(0x04)
 21     unsigned long NFCMD    ; //偏移地址: S3C2410_NFREG(0x08)
 22     unsigned long NFADDR   ; //偏移地址: S3C2410_NFREG(0x0C)
 23     unsigned long NFDATA   ; //偏移地址: S3C2410_NFREG(0x10)
 24     unsigned long NFECCD0  ; //偏移地址: S3C2410_NFREG(0x14)
 25     unsigned long NFECCD1  ; //偏移地址: S3C2410_NFREG(0x18)
 26     unsigned long NFECCD   ; //偏移地址: S3C2410_NFREG(0x1C)
 27     unsigned long NFSTAT   ; //偏移地址: S3C2410_NFREG(0x20)
 28     unsigned long NFESTAT0 ; //偏移地址: S3C2410_NFREG(0x24)
 29     unsigned long NFESTAT1 ; //偏移地址: S3C2410_NFREG(0x28)
 30     unsigned long NFMECC0  ; //偏移地址: S3C2410_NFREG(0x2C)
 31     unsigned long NFMECC1  ; //偏移地址: S3C2410_NFREG(0x30)
 32     unsigned long NFSECC   ; //偏移地址: S3C2410_NFREG(0x34)
 33     unsigned long NFSBLK   ; //偏移地址: S3C2410_NFREG(0x38)
 34     unsigned long NFEBLK   ; //偏移地址: S3C2410_NFREG(0x3C)
 35 };
 36
 37 static struct nand_chip *lhy_nand;
 38 static struct mtd_info *lhy_mtd;            //定义一个mtd_info结构体
 39 static struct lhy_nand_regs *lhy_nand_res;    //定义寄存器的结构体指针
 40
 41 /* 芯片选择 */
 42 static void lhy_select_chip(struct mtd_info *mtd,int chipnr)
 43 {
 44     if(chipnr == -1){
 45         /* 取消选中,NFCONT[1]设为0 */
 46         lhy_nand_regs->NFCONT |= (1<<1);
 47     }else{
 48         /* 选中:NFCONT[1]设为1 */
 49     lhy_nand_regs->NFCONT &= ~(1<<1);
 50     }
 51 }
 52 //发送命令,地址,数据
 53 static void lhy_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 54 {
 55     if (ctrl & NAND_CLE){
 56         /* 发命令 : NFCMMD=dat*/
 57         lhy_nand_regs->NFCMD = cmd;
 58     }else{
 59         writeb(cmd, host->io_base + (1 << host->board->ale));
 60         lhy_nand_regs->NFADDR = cmd;
 61     }
 62 }
 63 //判断状态
 64 static int lhy_dev_ready(struct mtd_info *mtd)
 65 {
 66     return (lhy_nand_regs->NFSTAT & (1<<0));
 67 }
 68
 69 static int lhy_nand_init(void){
 70
 71     /* 1.分配一个nand_chip结构体 */
 72     lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
 73
 74     lhy_nand_regs = ioremap(0x4E000000,sizeof(struct lhy_nand_regs)); //映射寄存器
 75     /* 2.设置 */
 76     /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用
 77      *         它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能
 78      */
 79     lhy_nand->select_chip = lhy_select_chip;          //选中,芯片选择函数
 80     lhy_nand->cmd_ctrl       = lhy_nand_cmd_ctrl;        //负责发送地址,命令
 81     lhy_nand->IO_ADDR_R   = lhy_nand_regs->NFDATA;    //读寄存器
 82     lhy_nand->IO_ADDR_W   = lhy_nand_regs->NFDATA;    //写寄存器
 83     lhy_nand->dev_ready      = lhy_dev_ready;            //判断状态
 84     nand_chip->ecc.mode = NAND_ECC_SOFT;            /*使能ECC校验码 enable ECC */
 85
 86     /* 3.硬件相关的操作 根据nand flash的手册设置时间参数
 87      * HCLK = 100MHz
 88      * TACLS: 发出CLE/ALE之后多长时间发出nWE信号,从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
 89      * TWRPH0: nWE的信号的脉冲宽度,HCLK *(TWPRH0 + 1),从NAND手册可知它要>=12ns,所以TWRPH0>=1
 90      * TWRPH1:表示nWE信号变为高电平后,CLE/ALE多长时间才能变为低电平,从手册可知他要>=5ns,所以TWRPH1>=0
 91      */
 92 #define TACLS     0
 93 #define TWRPH0    1
 94 #define TWRPH1    0
 95     lhy_nand_regs->NFCONF |= (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
 96
 97     /* NFCONT的bit1设为1,表示片 选 */
 98     lhy_nand_regs->NFCONT =  (1<<1) | (1<<0);
 99     /* 4.使用nand_scan */
100     lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
101     lhy_mtd->priv = lhy_nand;            //私有数据为我们的nand_chip结构体
102     lhy_mtd->owner = THIS_MODULE;
103
104     nand_scan(lhy_mtd,1);        //扫描识别nand flash,并且构造mtd,最大芯片个数为1
105     /* 5.add_mtd_partitions 添加分区 */
106     //add_mtd_partitions(tiny_nand_mtd, tiny_nand_part, 3);
107     return 0;
108 }
109
110 static void lhy_nand_exit(void){
111     if(lhy_nand)
112         kfree(lhy_nand);
113     if(lhy_mtd)
114         kfree(lhy_mtd);
115     if(lhy_nand_regs)
116         iounmap(lhy_nand_regs);
117 }
118
119 module_init(lhy_nand_init);
120 module_exit(lhy_nand_exit);
121 MODULE_LICENSE("GPL");
122
123
124 /*
125 S3C2440 U-BOOT 的NAND操作
126
127 1.读取ID
128 选中                    NFCONT的bit1设为0    md.1 0x4E000004 1;    mw.1 0x4e000004 1
129 发出命令0x90            NFCMMD=0X90            mw.b 0x4E000008 0x90
130 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
131 读出数据得到0XEC          val=NFDATA            md.b 0x4E000010 1
132 读数据得到device code    val=NFDATA             md.b 0x4E000010 1
133 退出读ID状态            NFCMMD=0xff            mw.b 0x4E000008 0xff
134
135 2.读内容 读0地址的数据
136 输入命令: nand dump 0  得到nand
137
138 选中                    NFCONT的bit1设为0    md.1 0x4E000004 1;    mw.1 0x4e000004 1
139 发出命令0x00            NFCMMD=0X00            mw.b 0x4E000008 0x00
140
141 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
142 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
143 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
144 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
145 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
146
147 发出命令0x30            NFCMMD=0X00            mw.b 0x4E000008 0x30
148
149 //接下来就是从0地址开始一个字节一个字节的读出数据,和前面nand dump 0 的数据一样
150 读出数据得到0x17          val=NFDATA            md.b 0x4E000010 1
151 读出数据得到0x00          val=NFDATA            md.b 0x4E000010 1
152 读出数据得到0x00          val=NFDATA            md.b 0x4E000010 1
153
154 退出读状态                NFCMMD=0xff            mw.b 0x4E000008 0xff
155
156 3.NAND  flash 驱动层次  Atmel_nand.c  Mtdchar.c
157 块设备:        知道怎么优化
158 NAND Flash协议:知道发什么来读写,擦除,识别
159 硬件相关:        知道怎样发命令/地址,读写数据
160
161 硬件相关:
162 ①分配nand_chip 结构体
163 ②设置nand_chip
164 ③硬件相关设备
165 ④使用 nand_scan / add_mtd_partitions
166
167
168 4.ECC校验码  64byte的OOB内存
169 flash每一页都有64B不参与编址,被称为OOB(out of bank)
170 原因是,nand flash的内存中,数据很容易发生位反转,为了防止数据出错,引入了ECC校验,
171 解决:①写一页的数据 ②用这一页的内容生成ECC校验码 ③把ECC校验码写入OOB中
172 读取:①读page ②读OOB里的ECC ③根据page的内容算ECC
173       ④将算的ECC校验码和读取OOB中的校验码进行校验和校准,可以算出哪一位发生错误。
174 ECC校验码生成:可以硬件也可以软件
175
176 */

nand flash3.c

四、增加分区挂接

要增加分区的话,首先要定义mtd_partition结构体,里面定义了分区的名字,起始地址,以及分区的大小等参数。

 1 //定义nand flash的分区
 2 static struct mtd_partition lhy_nand_part[] = {
 3     [0] = {
 4         .name    = "bootloader",
 5         .size    = 0x40000,
 6         .offset    = 0,
 7     },
 8     [1] = {
 9         .name    = "params",
10         .offset = MTDPART_OFS_APPEND,  //大小紧跟真前面这个分区
11         .size    = 0x20000,
12     },
13     [2] = {
14         .name    = "kernel",
15         .offset = MTDPART_OFS_APPEND,  //大小紧跟真前面这个分区
16         .size    = 0x200000,
17     },
18     [3] = {
19         .name    = "root",
20         .offset = MTDPART_OFS_APPEND,
21         .size    = MTDPART_SIZ_FULL,        //剩余的所有大小
22     },
23 };

接着就是在init函数中添加分区结构体。

1     /* 5.add_mtd_partitions 添加分区 */
2     //如果想整块flash只作为一个分区,使用add_mtd_device就够了
3     //add_mtd_device(lhy_mtd);
4     //如果要创建多个分区的话,那么就要使用add_mtd_partitions
5     add_mtd_partitions(lhy_nand_mtd, lhy_nand_part, 3);

附上驱动程序nand_flash4.c

  1 /*
  2  * 参考:linux-2.6.31\drivers\mtd\nand\s3c2410.c   atmel_nand.c
  3  */
  4
  5 #include <linux/slab.h>
  6 #include <linux/module.h>
  7 #include <linux/moduleparam.h>
  8 #include <linux/platform_device.h>
  9 #include <linux/mtd/mtd.h>
 10 #include <linux/mtd/nand.h>
 11 #include <linux/mtd/partitions.h>
 12 #include <linux/clk.h>
 13 #include <linux/io.h>
 14 #include <mach/board.h>
 15 #include <mach/cpu.h>
 16
 17 //寄存器结构体
 18 struct lhy_nand_regs{
 19     unsigned long NFCONF   ; //偏移地址: S3C2410_NFREG(0x00)
 20     unsigned long NFCONT   ; //偏移地址: S3C2410_NFREG(0x04)
 21     unsigned long NFCMD    ; //偏移地址: S3C2410_NFREG(0x08)
 22     unsigned long NFADDR   ; //偏移地址: S3C2410_NFREG(0x0C)
 23     unsigned long NFDATA   ; //偏移地址: S3C2410_NFREG(0x10)
 24     unsigned long NFECCD0  ; //偏移地址: S3C2410_NFREG(0x14)
 25     unsigned long NFECCD1  ; //偏移地址: S3C2410_NFREG(0x18)
 26     unsigned long NFECCD   ; //偏移地址: S3C2410_NFREG(0x1C)
 27     unsigned long NFSTAT   ; //偏移地址: S3C2410_NFREG(0x20)
 28     unsigned long NFESTAT0 ; //偏移地址: S3C2410_NFREG(0x24)
 29     unsigned long NFESTAT1 ; //偏移地址: S3C2410_NFREG(0x28)
 30     unsigned long NFMECC0  ; //偏移地址: S3C2410_NFREG(0x2C)
 31     unsigned long NFMECC1  ; //偏移地址: S3C2410_NFREG(0x30)
 32     unsigned long NFSECC   ; //偏移地址: S3C2410_NFREG(0x34)
 33     unsigned long NFSBLK   ; //偏移地址: S3C2410_NFREG(0x38)
 34     unsigned long NFEBLK   ; //偏移地址: S3C2410_NFREG(0x3C)
 35 };
 36
 37 static struct nand_chip *lhy_nand;
 38 static struct mtd_info *lhy_mtd;            //定义一个mtd_info结构体
 39 static struct lhy_nand_regs *lhy_nand_res;    //定义寄存器的结构体指针
 40
 41 //定义nand flash的分区
 42 static struct mtd_partition lhy_nand_part[] = {
 43     [0] = {
 44         .name    = "bootloader",
 45         .size    = 0x40000,
 46         .offset    = 0,
 47     },
 48     [1] = {
 49         .name    = "params",
 50         .offset = MTDPART_OFS_APPEND,  //大小紧跟真前面这个分区
 51         .size    = 0x20000,
 52     },
 53     [2] = {
 54         .name    = "kernel",
 55         .offset = MTDPART_OFS_APPEND,  //大小紧跟真前面这个分区
 56         .size    = 0x200000,
 57     },
 58     [3] = {
 59         .name    = "root",
 60         .offset = MTDPART_OFS_APPEND,
 61         .size    = MTDPART_SIZ_FULL,        //剩余的所有大小
 62     },
 63 };
 64
 65 /* 芯片选择 */
 66 static void lhy_select_chip(struct mtd_info *mtd,int chipnr)
 67 {
 68     if(chipnr == -1){
 69         /* 取消选中,NFCONT[1]设为0 */
 70         lhy_nand_regs->NFCONT |= (1<<1);
 71     }else{
 72         /* 选中:NFCONT[1]设为1 */
 73     lhy_nand_regs->NFCONT &= ~(1<<1);
 74     }
 75 }
 76 //发送命令,地址,数据
 77 static void lhy_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
 78 {
 79     if (ctrl & NAND_CLE){
 80         /* 发命令 : NFCMMD=dat*/
 81         lhy_nand_regs->NFCMD = cmd;
 82     }else{
 83         writeb(cmd, host->io_base + (1 << host->board->ale));
 84         lhy_nand_regs->NFADDR = cmd;
 85     }
 86 }
 87 //判断状态
 88 static int lhy_dev_ready(struct mtd_info *mtd)
 89 {
 90     return (lhy_nand_regs->NFSTAT & (1<<0));
 91 }
 92
 93 static int lhy_nand_init(void){
 94
 95     /* 1.分配一个nand_chip结构体 */
 96     lhy_nand = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
 97
 98     lhy_nand_regs = ioremap(0x4E000000,sizeof(struct lhy_nand_regs)); //映射寄存器
 99     /* 2.设置 */
100     /* 2.1设置nand_chip是给nand_scan函数用的,如果不知道怎么设置,先看nand_scan怎么用
101      *         它应该提供:选中,发命令,发地址,发数据,读数据,判断状态等功能
102      */
103     lhy_nand->select_chip = lhy_select_chip;          //选中,芯片选择函数
104     lhy_nand->cmd_ctrl       = lhy_nand_cmd_ctrl;        //负责发送地址,命令
105     lhy_nand->IO_ADDR_R   = lhy_nand_regs->NFDATA;    //读寄存器
106     lhy_nand->IO_ADDR_W   = lhy_nand_regs->NFDATA;    //写寄存器
107     lhy_nand->dev_ready      = lhy_dev_ready;            //判断状态
108     nand_chip->ecc.mode = NAND_ECC_SOFT;            /*使能软件ECC校验码 enable ECC */
109
110     /* 3.硬件相关的操作 根据nand flash的手册设置时间参数
111      * HCLK = 100MHz
112      * TACLS: 发出CLE/ALE之后多长时间发出nWE信号,从NAND手册可知CLE/ALE与nWE可以同时发出,所以TACLS=0
113      * TWRPH0: nWE的信号的脉冲宽度,HCLK *(TWPRH0 + 1),从NAND手册可知它要>=12ns,所以TWRPH0>=1
114      * TWRPH1:表示nWE信号变为高电平后,CLE/ALE多长时间才能变为低电平,从手册可知他要>=5ns,所以TWRPH1>=0
115      */
116 #define TACLS     0
117 #define TWRPH0    1
118 #define TWRPH1    0
119     lhy_nand_regs->NFCONF |= (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
120
121     /* NFCONT的bit1设为1,表示片 选 */
122     lhy_nand_regs->NFCONT =  (1<<1) | (1<<0);
123     /* 4.使用nand_scan */
124     lhy_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
125     lhy_mtd->priv = lhy_nand;            //私有数据为我们的nand_chip结构体
126     lhy_mtd->owner = THIS_MODULE;
127
128     nand_scan(lhy_mtd,1);        //扫描识别nand flash,并且构造mtd,最大芯片个数为1
129     /* 5.add_mtd_partitions 添加分区 */
130     //如果想整块flash只作为一个分区,使用add_mtd_device就够了
131     //add_mtd_device(lhy_mtd);
132     //如果要创建多个分区的话,那么就要使用add_mtd_partitions
133     add_mtd_partitions(lhy_nand_mtd, lhy_nand_part, 3);
134     return 0;
135 }
136
137 static void lhy_nand_exit(void){
138     del_mtd_partitions(lhy_nand_mtd);
139     if(lhy_nand)
140         kfree(lhy_nand);
141     if(lhy_mtd)
142         kfree(lhy_mtd);
143     if(lhy_nand_regs)
144         iounmap(lhy_nand_regs);
145 }
146
147 module_init(lhy_nand_init);
148 module_exit(lhy_nand_exit);
149 MODULE_LICENSE("GPL");
150
151
152 /*
153 S3C2440 U-BOOT 的NAND操作
154
155 1.读取ID
156 选中                    NFCONT的bit1设为0    md.1 0x4E000004 1;    mw.1 0x4e000004 1
157 发出命令0x90            NFCMMD=0X90            mw.b 0x4E000008 0x90
158 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
159 读出数据得到0XEC          val=NFDATA            md.b 0x4E000010 1
160 读数据得到device code    val=NFDATA             md.b 0x4E000010 1
161 退出读ID状态            NFCMMD=0xff            mw.b 0x4E000008 0xff
162
163 2.读内容 读0地址的数据
164 输入命令: nand dump 0  得到nand
165
166 选中                    NFCONT的bit1设为0    md.1 0x4E000004 1;    mw.1 0x4e000004 1
167 发出命令0x00            NFCMMD=0X00            mw.b 0x4E000008 0x00
168
169 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
170 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
171 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
172 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
173 发出地址0x00            NFADD=0X00            mw.b 0x4E00000c 0x00
174
175 发出命令0x30            NFCMMD=0X00            mw.b 0x4E000008 0x30
176
177 //接下来就是从0地址开始一个字节一个字节的读出数据,和前面nand dump 0 的数据一样
178 读出数据得到0x17          val=NFDATA            md.b 0x4E000010 1
179 读出数据得到0x00          val=NFDATA            md.b 0x4E000010 1
180 读出数据得到0x00          val=NFDATA            md.b 0x4E000010 1
181
182 退出读状态                NFCMMD=0xff            mw.b 0x4E000008 0xff
183
184 3.NAND  flash 驱动层次  Atmel_nand.c  Mtdchar.c
185 块设备:        知道怎么优化
186 NAND Flash协议:知道发什么来读写,擦除,识别
187 硬件相关:        知道怎样发命令/地址,读写数据
188
189 硬件相关:
190 ①分配nand_chip 结构体
191 ②设置nand_chip
192 ③硬件相关设备
193 ④使用 nand_scan / add_mtd_partitions
194
195
196 4.ECC校验码  64byte的OOB内存
197 flash每一页都有64B不参与编址,被称为OOB(out of bank)
198 原因是,nand flash的内存中,数据很容易发生位反转,为了防止数据出错,引入了ECC校验,
199 解决:①写一页的数据 ②用这一页的内容生成ECC校验码 ③把ECC校验码写入OOB中
200 读取:①读page ②读OOB里的ECC ③根据page的内容算ECC
201       ④将算的ECC校验码和读取OOB中的校验码进行校验和校准,可以算出哪一位发生错误。
202 ECC校验码生成:可以硬件也可以软件
203
204 5.测试3th
205 nfs挂载
206
207 1.去掉内核自带的NAND FLASH驱动
208 -->Device Drivers
209     -->Memory Technology Device (MTD) support
210         -->NAND Device Support
211         < > NAND Flash support for s3c2410 SoC
212 make uImage
213 2.保存以前的根文件系统的bootargs
214 nfs 30000000 192.168.1.5:/work/nfs_root/uImage_nonand
215 set bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.1.105:/work/nfs_root/first_fs ip=192.168.1.17:192.168.1.5:192.168.1.1:255.255.255.0::eth0:off
216
217 3.ls /dev/mtd*  //没有分区
218 4.insmod lhy_nand.ko
219 5.ls /dev/mtd*    //四个分区,总共有四对设备节点,只读与可写
220 6.格式化nand flash,工具:mtd_utils-06.7.23.tar.bz2
221     进入utils目录,修改Makefile,#CROSS=ARM-linux 修改为 CROSS=ARM-linux,把#号去掉
222     make
223 7.cp flash_erase flash_eraseall 拷贝到网络文件系统即可
224 8.flah_eraseall /dev/mtd2
225 9.挂接mount -t yaffs /dev/mtdblock3 /mnt/,可以在里面创建文件
226 10.接着重新启动开发板,重新装载模块,挂接,看看文件是否还在里面
227
228
229 */

nandflash4.c

时间: 2024-10-16 05:53:44

S3C2440 nand_flash驱动程序的相关文章

S3C2440 nor_flash驱动程序

20150418 S3C2440 nor_flash驱动程序 2015-04-18 Lover雪儿 和前面的nandflash差不多,我们此处来重新学习一下norflash驱动. 1 /* 2 * 参考 drivers\mtd\maps\Physmap.c 3 */ 4 5 #include <linux/module.h> 6 #include <linux/types.h> 7 #include <linux/kernel.h> 8 #include <lin

S3C2440实现dm9000网卡驱动程序移植

20150419 S3C2440实现dm9000网卡驱动程序移植 2015-04-19 Lover雪儿 首先附上厂家提供的完整的dm9000程序: 1 /* 2 3 dm9ks.c: Version 2.08 2007/02/12 4 5 A Davicom DM9000/DM9010 ISA NIC fast Ethernet driver for Linux. 6 7 This program is free software; you can redistribute it and/or

基于S3C2440的linux-3.6.6移植——LED驱动【转】

本文转载自:http://www.voidcn.com/blog/lqxandroid2012/article/p-625005.html 目前的linux版本的许多驱动都是基于设备模型,LED也不例外. 简单地说,设备模型就是系统认为所有的设备都是挂接在总线上的,而要使设备工作,就需要相应的驱动.设备模型会产生一个虚拟的文件系统——sysfs,它给用户提供了一个从用户空间去访问内核设备的方法,它在linux里的路径是/sys.如果要写程序访问sysfs,可以像读写普通文件一样来操作/sys目录

Android for S3C2440

转载: http://blog.csdn.net/blest/article/details/6215600 本人尚未尝试,先转载,以后再看. 1.移植基本环境: 我用的还是win的平台,所以使用了虚拟机:Vmware workstation 6.5.0 +ubuntu9.10: 交叉编译工具包EABI——4.3.3: 做好的镜像都是在win平台上使用串口烧录的 用到软件DNM: 启动之类的都用超级终端进行控制. 提示:TQ2440所附带的光盘中有很多有用的东西,建议大家看一下,所用的工具除了虚

S3C2440 驱动分层概念

为自己的坚持加油! 切入正题,今天要学习的是驱动的分层/分离概念. 分离分层的目的是将硬件相关的代码和系统中比较稳定的代码分离开,并且按照一定的框架联系到一起.这样我们在写一个驱动的时候能够更加灵活,顶层的应用程序也能更加稳定的调用底层的接口.对驱动开发者而言,这样写驱动程序将更有逻辑性.纯粹时个人理解哈. 以input.c框架为例,从图中可以看到系统把硬件相关的代码放在一起,把纯软件的相对稳定的部分放在一起,如evdev.c 最后他们通过input.c相连接. 除了输入子系统之外,设备总线也遵

linux驱动之触摸屏驱动程序

触摸屏归纳为输入子系统,这里主要是针对电阻屏,其使用过程如下 :当用触摸笔按下时,产生中断.在中断处理函数处理函数中启动ADC转换x,y坐标.ADC结束,产生ADC中断,在ADC中断处理函数里上报(input_event)启动定时器,再次启动定时器(可以处理滑动.长按),松开按键.其驱动程序的写法和之前写输入子系统的写法基本上一致.写出入口函数,出口函数并加以修饰,加入相关头文件,然后开始完善各函数,在入口函数中分配input_dev结构体,设置(能产生哪类事件,能产生这类事件中的哪些事件),注

linux下块设备驱动程序

块设备不能向字符设备那样访问,而是要先将请求放入队列,优化调整顺序后再执行,这种访问方式称为"电梯调度算法". 本篇文章通过ramdisk.nand flash.nor flash来讲解如何写块设备驱动程序. 一.ramdisk 1.因为块设备驱动程序是将请求放入队列然后调整顺序后执行,所以我们需要先定义请求队列: static unsigned char *ramblock_buf; ramblock_buf = kzalloc(RAMBLOCK_SIZE, GFP_KERNEL);

看门狗驱动程序

看门狗是当CPU进入错误状态后,无法恢复的情况下,使计算机重新启动 由于计算机在工作时不可避免的受到各种各样的因素干扰,即使再优秀的计算机程序也可能因为这种干扰使计算机进入一个死循环,更严重的就是导致死机. 有两种办法来处理这种情况: 一是:采用人工复位的方法 二是:依赖于某种硬件来执行这个复位工作.这种硬件通常叫做看门狗(Watch Dog,WD) 看门狗,就像一只狗一样,在那看着们,计算机中通常用定时器来处理这种周期性的动作 看门狗实际上是一个定时器,其硬件内部维护了一个定时器,每当时钟信号

I2C协议-&gt;裸机程序-&gt;adapter驱动程序分析

开发板:mini2440 内核  :linux2.6.32.2 参考  :韦东山毕业班I2C视频教程 1.i2c协议简要分析 i2c中线是一种由 PHILIPS 公司开发的串行总线,用于连接微控制器及其外围设备,它具有以下特点. 1.只有两条总线线路:一条串行数据线SDA,一条串行时钟线SCL. 2.每个连接到总线的器件都可以使用软件根据它的唯一的地址来确定. 3.传输数据的设备之间是简单的主从关系. 4.主机可以用作主机发送器或者主机接收器. 5.它是一个真正的多主机总线,两个或多个主机同时发