基于JZ2440的NOR FLASH的驱动程序的实现

来源:互联网 发布:windows rt刷安卓 编辑:程序博客网 时间:2024/05/29 16:59

本文的主要任务是实现JZ2440开发板板载的MX29LV800BBTC这款NOR FLASH驱动。


一、MX29LV800BBTC的简单介绍

这是一块容量为2MB,位宽为16位的NOR FLASH存储芯片,它可以像内存一样直接进行访问,但是不能像内存一样直接写入,它支持XIP。它的原理图如下所示:


它的引脚定义如下:

        LDATA0~LDATA15:数据引脚

        LADDR1~LADDR20:地址引脚

        LnOE:读使能引脚

        LnWE:写使能引脚

        nGCS0:片选引脚


二、驱动程序编写

驱动基于Linux-3.4.10内核编写。

1、一般实现步骤

a、分配一个map_info结构体变量

b、设置这个结构体变量

c、使用:do_map_probe()

d、添加分区

2、驱动程序编写

2.1 前期准备工作,为了方便整个驱动程序的编写,定义了全局结构体,并定义了一个该结构体的全局变量,具体实现如下:

/* 构造一个方便编写驱动程序的结构体 */struct yl_nor_mtd{struct map_info *map_info;// 定义map_info结构体的指针变量struct mtd_info *mtd_info;// 定义mtd_info结构体的指针变量};/* 定义一个yl_nor_mtd结构体的全局变量 */static struct yl_nor_mtd nor_mtd;
2.2 分配一个map_info结构体的指针变量

/* 1、分配一个map_info结构体变量 */nor_mtd.map_info = kzalloc(sizeof(struct map_info), GFP_KERNEL);

2.3 设置这个结构体变量

/* 2、设置 */nor_mtd.map_info->name = "yl_nor_flash";// 名字nor_mtd.map_info->phys = 0;// 物理基地址nor_mtd.map_info->size = 0x200000; // 尺寸,>=真实大小nor_mtd.map_info->bankwidth = 2;// 位宽/* 设置虚拟地址的基地址 */nor_mtd.map_info->virt = ioremap(nor_mtd.map_info->phys, nor_mtd.map_info->size);if (nor_mtd.map_info->virt == NULL) {printk("Failed to ioremap flash region\n");ret = -EIO;goto out2;}/* 其他的nor flash的通用的初始化 */simple_map_init(nor_mtd.map_info);
2.4 使用这个结构体变量,获得一个mtd_info结构体变量的实例

/* 3、使用 */nor_mtd.mtd_info = do_map_probe("cfi_probe", nor_mtd.map_info);if(nor_mtd.mtd_info == NULL){printk("do_map_probe for cfi_probe failure!\n");ret = -ENXIO;goto out3;}
2.5 添加分区

/* 4、添加分区 */ret = mtd_device_parse_register(nor_mtd.mtd_info, NULL, NULL,yl_s3c_nor_partitions, ARRAY_SIZE(yl_s3c_nor_partitions));
添加分区需要有一个分区表作为分区依据,分区表的实现如下所示:

/* 定义nor flash的分区表 */static struct mtd_partition yl_s3c_nor_partitions[] = {[0] = {.name= "bootloader_nor",.size= SZ_256K,.offset= 0,},[1] = {.name= "params_nor",.offset = MTDPART_OFS_APPEND,.size= SZ_128K,},[2] = {.name= "rootfs_nor",.offset= MTDPART_OFS_APPEND,.size= MTDPART_SIZ_FULL,}};


整个驱动的完整代码如下所示:
#include <linux/module.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/mtd/mtd.h>#include <linux/mtd/map.h>#include <linux/mtd/partitions.h>#include <linux/mtd/concat.h>#include <linux/io.h>/* 构造一个方便编写驱动程序的结构体 */struct yl_nor_mtd{struct map_info *map_info;// 定义map_info结构体的指针变量struct mtd_info *mtd_info;// 定义mtd_info结构体的指针变量};/* 定义一个yl_nor_mtd结构体的全局变量 */static struct yl_nor_mtd nor_mtd;/* 定义nor flash的分区表 */static struct mtd_partition yl_s3c_nor_partitions[] = {[0] = {.name= "bootloader_nor",.size= SZ_256K,.offset= 0,},[1] = {.name= "params_nor",.offset = MTDPART_OFS_APPEND,.size= SZ_128K,},[2] = {.name= "rootfs_nor",.offset= MTDPART_OFS_APPEND,.size= MTDPART_SIZ_FULL,}};/* 模块的入口函数 */static int __init yl_s3c_nor_init(void){int ret = 0;/* 1、分配一个map_info结构体变量 */nor_mtd.map_info = kzalloc(sizeof(struct map_info), GFP_KERNEL);if (!nor_mtd.map_info) {printk("kzalloc for map_info error!\n");ret = -ENOMEM;goto out1;}/* 2、设置 */nor_mtd.map_info->name = "yl_nor_flash";// 名字nor_mtd.map_info->phys = 0;// 物理基地址nor_mtd.map_info->size = 0x200000; // 尺寸,>=真实大小nor_mtd.map_info->bankwidth = 2;// 位宽/* 设置虚拟地址的基地址 */nor_mtd.map_info->virt = ioremap(nor_mtd.map_info->phys, nor_mtd.map_info->size);if (nor_mtd.map_info->virt == NULL) {printk("Failed to ioremap flash region\n");ret = -EIO;goto out2;}/* 其他的nor flash的通用的初始化 */simple_map_init(nor_mtd.map_info);/* 3、使用 */nor_mtd.mtd_info = do_map_probe("cfi_probe", nor_mtd.map_info);if(nor_mtd.mtd_info == NULL){printk("do_map_probe for cfi_probe failure!\n");ret = -ENXIO;goto out3;}/* 4、添加分区 */ret = mtd_device_parse_register(nor_mtd.mtd_info, NULL, NULL,yl_s3c_nor_partitions, ARRAY_SIZE(yl_s3c_nor_partitions));if(ret)// 失败{printk("mtd_device_parse_register error!\n");ret = -ENODEV;goto out3;}else// 成功{return 0;}out3:iounmap(nor_mtd.map_info->virt);out2:kfree(nor_mtd.map_info);out1:return ret;}/* 模块的出口函数 */static void __exit yl_s3c_nor_exit(void){/* 进行出口的一些操作,释放资源,解除绑定,取消注册 */mtd_device_unregister(nor_mtd.mtd_info);iounmap(nor_mtd.map_info->virt);kfree(nor_mtd.map_info);}module_init(yl_s3c_nor_init);module_exit(yl_s3c_nor_exit);MODULE_LICENSE("GPL");

3、编译驱动程序并把模块加载进内核,结果如下所示:



原创粉丝点击