驱动程序之_2_块设备_4_Nand Flash_3_驱动程序编写
参考/drivers/mtd/nand/目录下的s3c2410.c和At91_nand.c
一、入口函数
1、分配nand_chip
2、设置nand_chip(如果不知道怎么设置,可以从nand_scan函数入手分析,如果不设置,会分配有默认值、默认函数,可以参数默认函数编写符合自己的函数,如果默认函数可用,可以不额外编写)
3、硬件设置(首先要开启时钟)
4、分配mtd_info
5、扫描构造mtd_info
6、添加mtd分区
二、出口函数,完成与入口函数相反的操作
三、完善功能函数
1、片选控制
2、命令、地址传送
3、状态检测
测试步骤:
1、重新编译内核(反选内核的nand flash驱动),用新内核,并从网络文件系统启动
| Location: |
| -> Device Drivers |
| -> Memory Technology Device (MTD) support (MTD [=y]) |
| -> NAND Device Support (MTD_NAND [=y]) |
| -> NAND Flash support for S3C2410/S3C2440 SoC (MTD_NAND_S3C2410 [=n])
2、加载驱动
3、查看设备
ls /dev/mtd*
4、挂载设备
mkdir /mnt
mount /dev/mtdblock3 /mnt
5、格式化(网上下载mtd-utils-05.07.23.tar.bz2,送到服务器解压,进入解压目录下的util目录,修改Makefile,反注释CROSS=arm-linux-,编译make,拷贝flash_erase、flash_eraseall到网络文件系统/bin目录中)
擦除后默认就是yaffs格式
umount /mnt
flash_eraseall /dev/mtd3
6、再挂载
mount -t yaffs /dev/mtdblock3 /mnt
7、可以参考前面块设备简单实例的测试方法继续测试
附上完整代码
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/clk.h>
#include <asm/io.h>
#include <asm/sizes.h>
#include <asm/hardware.h>
#include <asm/arch/gpio.h>
#define PARTITIONS
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
static struct mtd_partition s3c2440_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,
}
};
struct s3c2440_nand_regs{
unsigned long nfconf;
unsigned long nfcont;
unsigned long nfcmmd;
unsigned long nfaddr;
unsigned long nfdata;
unsigned long nfeccd0;
unsigned long nfeccd1;
unsigned long nfeccd;
unsigned long nfstat;
unsigned long nfestat0;
unsigned long nfestat1;
unsigned long nfmecc0;
unsigned long nfmecc1;
unsigned long nfsecc;
unsigned long nfsblk;
unsigned long nfeblk;
};
static struct nand_chip *s3c2440_nand_chip;
static struct mtd_info *s3c2440_mtd;
static struct s3c2440_nand_regs *s3c2440_nand_regs;
static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chipnr)
{
if(chipnr == -1)
{
s3c2440_nand_regs->nfcont |= (1<<1);
}
else
{
s3c2440_nand_regs->nfcont &= ~(1<<1);
}
}
static void s3c2440_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
{
if(ctrl & NAND_CLE)
s3c2440_nand_regs->nfcmmd = dat;
else
s3c2440_nand_regs->nfaddr = dat;
}
static int s3c2440_nand_ready(struct mtd_info *mtd)
{
return (s3c2440_nand_regs->nfstat & (1<<0));
}
static int nand_init(void)
{
struct clk *nand_clk;
s3c2440_nand_chip = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
s3c2440_nand_regs = ioremap(0x4e000000,sizeof(struct s3c2440_nand_regs));
nand_clk = clk_get(0,"nand");
clk_enable(nand_clk);
s3c2440_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4);
s3c2440_nand_regs->nfcont = (1<<1) | (1<<0);
s3c2440_nand_chip->select_chip = s3c2440_nand_select_chip;
s3c2440_nand_chip->IO_ADDR_R = &s3c2440_nand_regs->nfdata; //virtual addr
s3c2440_nand_chip->IO_ADDR_W = &s3c2440_nand_regs->nfdata;
s3c2440_nand_chip->cmd_ctrl = s3c2440_nand_cmd_ctrl;
s3c2440_nand_chip->dev_ready = s3c2440_nand_ready;
s3c2440_nand_chip->ecc.mode = NAND_ECC_SOFT;
s3c2440_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
s3c2440_mtd->owner = THIS_MODULE;
s3c2440_mtd->priv = s3c2440_nand_chip;
nand_scan(s3c2440_mtd,1);
#ifdef PARTITIONS
add_mtd_partitions(s3c2440_mtd, s3c2440_nand_parts, 4); //分区
#else
add_mtd_device(s3c2440_mtd); //不分区
#endif
return 0;
}
static void nand_exit(void)
{
#ifdef PARTITIONS
del_mtd_partitions(s3c2440_mtd);
#else
del_mtd_device(s3c2440_mtd);
#endif
kfree(s3c2440_mtd);
iounmap(s3c2440_nand_regs);
kfree(s3c2440_nand_chip);
}
module_init(nand_init);
module_exit(nand_exit);
MODULE_LICENSE("GPL");