Nand flash Driver kernel implementation analysis process:
Analysis code
Handler // drivers/mtd/nand/nand_base.c identify nand flash based on nand_chip's underlying operation function and construct mtd_info nand_scan_ident nand_set_defaults if (! Chip-> select_chip) chip-> select_chip = nand_select_chip; // The default value is not applicable if (chip-> program func = NULL) chip-> program func = nand_command; chip-> program _ctrl (mtd, command, ctrl); if (! Chip-> read_byte) chip-> read_byte = nand_read_byte; readb (chip-> IO_ADDR_R); if (chip-> waitfunc = NULL) chip-> waitfunc = nand_wait; chip-> dev_ready nand_get_flash_type chip-> select_chip (mtd, 0); chip-> 1_func (mtd, nand_1__readid, 0x00,-1 ); * maf_id = chip-> read_byte (mtd); dev_id = chip-> read_byte (mtd); nand_scan_tail mtd-> erase = nand_erase; mtd-> read = nand_read; mtd-> write = nand_write; s3c2410_nand_add_partition add_mtd_partitions add_mtd_device list_for_each (this, & mtd_notifiers) {// ask. where can mtd_notifiers be set? //. drivers/mtd/mtdchar. c, mtd_blkdev.c call register_mtd_user struct mtd_notifier * not = list_entry (this, struct mtd_notifier, list); not-> add (mtd ); // mtd_policy_add and blktrans_policy_add read the mtd_policy_add class_device_create of the character device and then the list_for_each (this, & blktrans_majors) of the block device {// ask. where can I set blktrans_majors? //. drivers \ mtd \ mdblock. c or mtdblock_ro.c returns struct mtd_blktrans_ops * tr = list_entry (this, struct mtd_blktrans_ops, list); tr-> add_mtd (tr, mtd); Digest (drivers \ mtd \ mdblock. c) add_mtd_blktrans_dev alloc_disk gd-> queue = tr-> blkcore_priv-> rq; // tr-> blkcore_priv-> rq = blk_init_queue (mtd_blktrans_request, & tr-> blkcore_priv-> queue_lock); add_disk
Nand flash Driver Design Process:
Nand flash Driver code design:
Initi_nand.c
/* Refer to * 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. h> # include <linux/mtd/nand. h> # includ E <linux/mtd/nand_ecc.h> # include <linux/mtd/partitions. h> # include <asm/io. h & gt; # include <asm/arch/regs-nand.h> # include <asm/arch/nand. h> struct detail {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 l Ong nfestat1; unsigned long nfmecc0; unsigned long nfmecc1; unsigned long nfsecc; unsigned long listener;}; static struct nand_chip * initi_nand; static struct mtd_info * initi_mtd; static struct initi_nand_regs * initi_nand_regs; static struct mtd_partition initi_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 s3c2440_select_chip (struct mtd_info * mtd, int chipnr) {if (chipnr =-1) {/* uncheck: NFCONT [1] is set to 1 */initi_nand_regs-> nfcont | = (1 <1);} else {/* selected: NFCONT [1] is set to 0 */initi_nand_regs-> nfcont & = ~ (1 <1) ;}} static void s3c2440_1__ctrl (struct mtd_info * mtd, int dat, unsigned int ctrl) {if (ctrl & NAND_CLE) {/* command: NFCMMD = dat */initial_nand_regs-> nfcmd = dat;} else {/* address: NFADDR = dat */initial_nand_regs-> nfaddr = dat ;}} static int s3c2440_dev_ready (struct mtd_info * mtd) {return (initi_nand_regs-> nfstat & (1 <0);} static int initi_nand_init (void) {struct clk * clk; /* 1. assign an nand_chip struct */initial_nand = kzarloc (sizeof (struct nand_chip), GFP_KERNEL); struct = ioremap (0x4E000000, sizeof (struct initi_nand_regs);/* 2. set nand_chip * // * To set nand_chip for the nand_scan function. If you do not know how to set nand_scan, see how nand_scan is used. * It should provide: Select, send command, and send address, data sending, reading, and status determination functions */initi_nand-> select_chip = s3c2440_select_chip; initi_nand-> export _ctrl = s3c2440_1__ctrl; initi_nand-> IO_ADDR_R = & initi_nand_regs-> nfdata; ap-southeast-1. mode = NAND_ECC_SOFT;/* 3. hardware-related settings: set the time parameter * // * According to the nand flash manual to enable the clock of the nand flash Controller */clk = clk_get (NULL, "nand "); clk_enable (clk);/* CLKCON 'bit [4] * // * HCLK = 100 MHz * TACLS: How long does it take to send nWE signals after the CLE/ALE is sent, we can see from the NAND manual that CLE/ALE and nWE can be issued at the same time, So TACLS = 0 * TWRPH0: nWE pulse width, HCLK x (TWRPH0 + 1 ), we can see from the NAND manual that it must be greater than or equal to 12ns, so TWRPH0> = 1 * TWRPH1: how long will the CLE/ALE become low after the nWE becomes high, we can see from the NAND manual that it must be greater than or equal to 5ns, so TWRPH1> = 0 */# define TACLS 0 # define TWRPH0 1 # define TWRPH1 0 initi_nand_regs-> nfconf =) | (TWRPH0 <8) | (TWRPH1 <4);/* NFCONT: * BIT1-set to 1, deselect * BIT0-set to 1, enable the nand flash Controller */cloud_nand_regs-> nfcont = (1 <1) | (1 <0);/* 4. use: nand_scan */89c_mtd = kzarloc (sizeof (struct mtd_info), role); initi_mtd-> owner = THIS_MODULE; Role-> priv = initi_nand; nand_scan (initi_mtd, 1 ); /* Identify nand flash and construct mtd_info * // * 5. optional */values (initi_mtd, numbers, 4); // add_mtd_device (initi_mtd); return 0;} static void initi_nand_exit (void) {del_mtd_partitions (initi_mtd); kfree (initi_mtd ); iounmap (cloud_nand_regs); kfree (cloud_nand);} module_init (cloud_nand_init); module_exit (cloud_nand_exit); MODULE_LICENSE ("GPL ");