重要結構體
nand_chip
struct nand_chip { void __iomem *IO_ADDR_R; void __iomem *IO_ADDR_W; uint8_t (*read_byte)(struct mtd_info *mtd); u16 (*read_word)(struct mtd_info *mtd); void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len); int (*verify_buf)(struct mtd_info *mtd, const uint8_t *buf, int len); void (*select_chip)(struct mtd_info *mtd, int chip); int (*block_bad)(struct mtd_info *mtd, loff_t ofs, int getchip); int (*block_markbad)(struct mtd_info *mtd, loff_t ofs); void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); int (*dev_ready)(struct mtd_info *mtd); void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); void (*erase_cmd)(struct mtd_info *mtd, int page); int (*scan_bbt)(struct mtd_info *mtd); int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf, int page, int cached, int raw); int chip_delay; unsigned int options; int page_shift; int phys_erase_shift; int bbt_erase_shift; int chip_shift; int numchips; unsigned long chipsize; int pagemask; int pagebuf; int subpagesize; uint8_t cellinfo; int badblockpos; nand_state_t state; uint8_t *oob_poi; struct nand_hw_control *controller; struct nand_ecclayout *ecclayout; struct nand_ecc_ctrl ecc; struct nand_buffers *buffers; struct nand_hw_control hwcontrol; struct mtd_oob_ops ops; uint8_t *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; struct nand_bbt_descr *badblock_pattern; void *priv;};
重要函式呼叫過程
1,int nand_scan(struct mtd_info *mtd, int maxchips)2,int nand_scan_ident(struct mtd_info *mtd, int maxchips)3,nand_set_defaults4,static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, int busw, int *maf_id)5,int nand_scan_tail(struct mtd_info *mtd)
驅動程式編寫思路(1)分配一個nand_chip和mtd_info結構體(2)根據自己的需要,構造nand_chip結構體。以及一些硬體相關的設定(3)最後就是呼叫nand_scan()和add_mtd_partitions()函式
程式原始碼:
/* 參考 * drivers\mtd\nand\s3c2410.c * drivers\mtd\nand\at91_nand.c */#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> #include <asm/arch/regs-nand.h>#include <asm/arch/nand.h>#define NAND_CHIP_NUM 1#define TACLS 0#define TWRPH0 1#define TWRPH1 0 struct s3c_nand_regs { unsigned long nfconf ; unsigned long nfcont ; unsigned long nfcmd ; 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 s3c_nand_regs *s3c_nand_regs;static struct nand_chip * nand_block;static struct mtd_info * nand_mtd;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 void configurate_nand_chip(void);static int s3c2440_dev_ready(struct mtd_info *mtd);static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl);static void nand_select_chip(struct mtd_info *mtd, int chipnr);static int nand_block_init(void){ nand_block = kzalloc(sizeof(struct nand_chip), GFP_KERNEL); configurate_nand_chip(); nand_mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); nand_mtd->owner = THIS_MODULE; nand_mtd->priv = nand_block; nand_scan(nand_mtd,NAND_CHIP_NUM); add_mtd_partitions(nand_mtd, s3c_nand_parts, 4); return 0;}static void nand_block_exit(void){ del_mtd_partitions(nand_mtd); kfree(nand_mtd); iounmap(s3c_nand_regs); kfree(nand_block); }static int s3c2440_dev_ready(struct mtd_info *mtd){ return (s3c_nand_regs->nfstat & (1<<0));}static void s3c2440_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl){ if (ctrl & NAND_CLE) { s3c_nand_regs->nfcmd = dat; } else { s3c_nand_regs->nfaddr = dat; }}static void nand_select_chip(struct mtd_info *mtd, int chipnr){ switch (chipnr) { case -1: s3c_nand_regs->nfcont |= (1<<1); break; case 0: s3c_nand_regs->nfcont &= ~(1<<1); break; default: BUG(); }}static void configurate_nand_chip(void){ struct clk *clk; s3c_nand_regs = ioremap(0x4E000000, sizeof(struct s3c_nand_regs)); nand_block->select_chip = nand_select_chip; nand_block->cmd_ctrl = s3c2440_cmd_ctrl; nand_block->IO_ADDR_R = &s3c_nand_regs->nfdata; nand_block->IO_ADDR_W = &s3c_nand_regs->nfdata; nand_block->dev_ready = s3c2440_dev_ready; nand_block->ecc.mode = NAND_ECC_SOFT; clk = clk_get(NULL, "nand"); clk_enable(clk); s3c_nand_regs->nfconf = (TACLS<<12) | (TWRPH0<<8) | (TWRPH1<<4); s3c_nand_regs->nfcont = (1<<1) | (1<<0); }module_init(nand_block_init);module_exit(nand_block_exit);MODULE_LICENSE("GPL");
Makefile
#compile regularKERN_DIR = /work/system/linux-2.6.22.6all: make -C $(KERN_DIR) M=`pwd` modules rm -rf modules.order Module.symvers .PHONY:clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order Module.symversobj-m += nand_block.o