linux设备驱动——NandFlash驱动程序

来源:互联网 发布:从零开始学日语软件 编辑:程序博客网 时间:2024/06/13 02:22

首先要来弄明白Nand的硬件操作原理,



1. 读ID
                                            
选中                                    NFCONT的bit1设为0   
发出命令0x90                   NFCMMD=0x90         
发出地址0x00                   NFADDR=0x00         
读数据得到0xEC                 val=NFDATA          
读数据得到device code           val=NFDATA          
退出读ID的状态                 NFCMMD=0xff         
     
2. 读内容: 读0地址的数据
                                                   
选中                               NFCONT的bit1设为0   
发出命令0x00                   NFCMMD=0x00         
发出地址0x00                   NFADDR=0x00         
发出地址0x00                   NFADDR=0x00         
发出地址0x00                   NFADDR=0x00         
发出地址0x00                   NFADDR=0x00         
发出地址0x00                   NFADDR=0x00         
发出命令0x30                   NFCMMD=0x30         
读数据得到0x17                 val=NFDATA          
读数据得到0x00                 val=NFDATA          
读数据得到0x00                 val=NFDATA          
读数据得到0xea                 val=NFDATA          
退出读状态                     NFCMMD=0xff         



nand是块设备,也遵循块设备驱动那一套,当应用程序调用open,read,write时,文件系统会转化成对扇区的读写请求,并且把请求优化后放入一个队列中,然后调用队列的处理函数用电梯调度算法从队列中取出请求进行处理。

nand的协议很复杂,所以内核把共性的东西都给写好了,我们只需要提供一个结构体,里面是有差异的东西,然后调用内核中写好的函数使用这个结构体来完成那一套的操作。

所以nand驱动就变成

1.构造nand_chip结构体

2.调用内核中的的nand_scan函数来完成那一套操作。

3.add_mtd_partitions



#include <linux/module.h>#include <linux/types.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/platform_device.h>#include <linux/delay.h>#include <linux/err.h>#include <linux/slab.h>#include <linux/clk.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <linux/mtd/partitions.h>#include <asm/io.h>struct nand_regs{unsigned long NFCONF  ;unsigned long NFCONT  ;unsigned long NFCMD   ;unsigned long NFADDR  ;unsigned long NFDATA  ;unsigned long NFMECC0_1 ;unsigned long NFMECC1_1 ;unsigned long NFSECC_1  ;unsigned long NFSTAT  ;unsigned long NFESTAT0;unsigned long NFESTAT1;unsigned long NFMECC0_2 ;unsigned long NFMECC1_2 ;unsigned long NFSECC_2  ;unsigned long NFSBLK  ;unsigned long NFEBLK  ;};static struct mtd_partition s3c_nand_parts[] = {[0] = {        .name   = "bootloader",        .size   = 0x00040000,.offset= 0,},[1] = {        .name   = "params",        .offset = MTDPART_OFS_APPEND,        .size   = 0x00020000,},[2] = {        .name   = "kernel",        .offset = MTDPART_OFS_APPEND,        .size   = 0x00200000,},[3] = {        .name   = "root",        .offset = MTDPART_OFS_APPEND,        .size   = MTDPART_SIZ_FULL,}};static struct nand_chip *nand_chip;static struct nand_regs *nand_regs;static struct mtd_info  *s3c_nand_mtd_info;static void s3c_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl){if (ctrl & NAND_CLE)/*写命令*/nand_regs->NFCMD = cmd;else/*写地址*/nand_regs->NFADDR= cmd;}static void nand_select_chip(struct mtd_info *mtd, int chipnr){switch (chipnr) {case -1:/*取消选中*/nand_regs->NFCONT |= (1<<1);break;case 0:/*选中芯片*/nand_regs->NFCONT &= ~(1<<1);break;default:BUG();}}static int s3c_nand_device_ready(struct mtd_info *mtd){return ((nand_regs->NFSTAT)&1);}static int nand_init(void){struct clk *clk;nand_regs = ioremap(0x4E000000,sizeof(struct nand_regs));nand_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);nand_chip->select_chip   = nand_select_chip;nand_chip->cmd_ctrl = s3c_nand_cmd_ctrl;nand_chip->IO_ADDR_R    = &(nand_regs->NFDATA);nand_chip->IO_ADDR_W   = &(nand_regs->NFDATA);nand_chip->dev_ready      = s3c_nand_device_ready;nand_chip->ecc.mode    = NAND_ECC_SOFT;s3c_nand_mtd_info = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);s3c_nand_mtd_info->owner = THIS_MODULE;s3c_nand_mtd_info->priv = nand_chip;clk = clk_get(NULL, "nand");clk_enable(clk);              /* CLKCON'bit[4] */#define TACLS    0#define TWRPH0   1#define TWRPH1   0nand_regs->NFCONF= (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);nand_regs->NFCONT= (1<<1) | (1<<0);nand_scan(s3c_nand_mtd_info,1);add_mtd_partitions(s3c_nand_mtd_info,s3c_nand_parts,4);return 0;}static void nand_exit(void){del_mtd_partitions(s3c_nand_mtd_info);kfree(s3c_nand_mtd_info);iounmap(nand_regs);kfree(nand_chip);}module_init(nand_init);module_exit(nand_exit);MODULE_LICENSE("GPL");

0 0
原创粉丝点击