环境:debian 6 linux 2.6.35.7
arm-linux-gcc:
做完核心的内核移植之后,接下来要做的驱动移植,第一步移植的是nand flash驱动。
在做驱动移植之前,我们有必要了解一下linux的platform机制:
从Linux 2.6起引入了一套新的驱动管理和注册机制:platform_device和platform_driver。Linux中大部分的设备驱动,都可以使用这套机制,设备用platform_device表示,驱动用platform_driver进行注册。
Linux platform. driver机制和传统的device driver 机制(通过driver_register函数进行注册)相比,一个十分明显的优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序中使用这些资源时通过platform. device提供的标准接口进行申请并使用。这样提高了驱动和资源管理的独立性,并且拥有较好的可移植性和安全性(这些标准接口是安全的)。platform机制的本身使用并不复杂,由两部分组成:platform_device和platfrom_driver。通过platform机制开发底层设备驱动的大致流程如图所示。
platform机制开发驱动流程
platform_device结构体用来描述设备的名称、资源信息等。该结构被定义在include/linux/platform_device.h中,定义原型如下:
struct platform_device {
const char * name; //定义平台设备的名称
int id;
struct device dev;
u32 num_resources;
struct resource * resource; //定义平台设备的资源。
};
下面来看一下platform_device结构体中最重要的一个成员struct resource * resource。struct resource被定义在include/linux/ioport.h中,定义原型如下:
struct resource {
resource_size_t start; //定义资源的起始地址
resource_size_t end; //定义资源的结束地址
const char *name; //定义资源的名称
unsigned long flags; //定义资源的类型,比如MEM,IO,IRQ,DMA类型
struct resource *parent, *sibling, *child; //资源链表指针
};
通过调用函数platform_add_devices()向系统中添加该设备了,该函数内部调用platform_device_register( )进行设备注册。要注意的是,这里的platform_device设备的注册过程必须在相应设备驱动加载之前被调用,即执行platform_driver_register()之前,原因是驱动注册时需要匹配内核中所有已注册的设备名。
接下来来看platform_driver结构体的原型定义,在include/linux/platform_device.h中,代码如下:
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*suspend_late)(struct platform_device *, pm_message_t state);
int (*resume_early)(struct platform_device *);
int (*resume)(struct platform_device *);
struct device_driver driver;
};
内核提供的platform_driver结构体的注册函数为platform_driver_register(),其原型定义在driver/base/platform.c文件中,具体实现代码如下:
int platform_driver_register(struct platform_driver *drv)
{
drv->driver.bus = &platform_bus_type;
if (drv->probe)
drv->driver.probe = platform_drv_probe;
if (drv->remove)
drv->driver.remove = platform_drv_remove;
if (drv->shutdown)
drv->driver.shutdown = platform_drv_shutdown;
if (drv->suspend)
drv->driver.suspend = platform_drv_suspend;
if (drv->resume)
drv->driver.resume = platform_drv_resume;
return driver_register(&drv->driver);
}
总结,通常情况下只要和内核本身运行依赖性不大的外围设备,相对独立的,拥有各自独自的资源(地址总线和IRQs),都可以用platform_driver实现。如:LCD,网卡、USB、UART等,都可以用platfrom_driver写,而timer,irq等小系统之内的设备则最好不用platfrom_driver机制。
以上关于platfrom机制均为网络转载。
现在开始来进行nand flash驱动移植
首先下载nand flash驱动 s3c_nand.c ,此文件包含着nand flash驱动具体的实现,将其复制到drivers/mtd/nand下;
s3c_nand.c 下载地址 s3c_nand.c
在s3c_nand.c中添加nand flash分区信息,分区内容可以自由设定。
#if defined(CONFIG_ARCH_S5PV210)
struct mtd_partition s3c_partition_info[] = {
{
.name= "misc",
.offset= (768*SZ_1K), /* for bootloader */
.size= (256*SZ_1K),
.mask_flags= MTD_CAP_NANDFLASH,
},
{
.name= "recovery",
.offset= MTDPART_OFS_APPEND,
.size= (5*SZ_1M),
},
{
.name= "kernel",
.offset= MTDPART_OFS_APPEND,
.size= (5*SZ_1M),
},
{
.name= "ramdisk",
.offset= MTDPART_OFS_APPEND,
.size= (3*SZ_1M),
},
{
.name= "system",
.offset= MTDPART_OFS_APPEND,
.size= MTDPART_SIZ_FULL,
}
{
.name= "system",
.offset= MTDPART_OFS_APPEND,
.size= (110*SZ_1M),
},
{
.name= "cache",
.offset= MTDPART_OFS_APPEND,
.size= (80*SZ_1M),
},
{
.name= "userdata",
.offset= MTDPART_OFS_APPEND,
.size= MTDPART_SIZ_FULL,
}
#endif
};
struct s3c_nand_mtd_info s3c_nand_mtd_part_info = {
.chip_nr = 1,
.mtd_part_nr = ARRAY_SIZE(s3c_partition_info),
.partition = s3c_partition_info,
};
结构体s3c_nand_mtd_info在源代码是没有的,所以要将其添加进去;
为了能使s3c_nand.c正确编译,还要修改该目录下,也就是的drivers/mtd/nand的Makefile和Kconfig:
在Mach-smdkv210.c (arch\arm\mach-s5pv210) 中添加nand flash source,platform_device,需要头文件map.h map.h下载,下载将其放在(arch\arm\mach-s5pv210\include\mach),在Mach-smdkv210.c中加入#include
添加nand flash source
/* NAND Controller */
static struct resource s3c_nand_resource[] = {
[0] = {
.start= S5PV210_PA_NAND,
.end= S5PV210_PA_NAND + S5PV210_SZ_NAND - 1,
.flags= IORESOURCE_MEM,
}
};
struct platform_device s3c_device_nand = {
.name= "s5pv210-nand",
.id= -1,
.num_resources= ARRAY_SIZE(s3c_nand_resource),
.resource= s3c_nand_resource,
};
添加platform_device
找到static struct platform_device *smdkv210_devices[] __initdata
添加
添加时钟信息
在Clock.c (arch\arm\mach-s5pv210) 中找到static struct clk init_clocks_off[],添加
{
.name = "nand",
.id = -1,
.parent = &clk_hclk_psys.clk,
.enable = s5pv210_clk_ip1_ctrl,
.ctrlbit = ((1 << 28) | (1 << 24)),
},
添加之后,nand flash驱动才能正确获取时钟。
以上操作完成后,开始配置内核
根目录下make menuconfig
到了这里,开发板已经支持nand flash驱动。
接下来
配置后保存,make clean ,make zImage
将zImage下载进开发板。从串口信息可以看出nand flash驱动是否完成:
S3C NAND Driver, (c) 2008 Samsung Electronics
S3C NAND Driver is using hardware ECC.
NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
Creating 5 MTD partitions on "s5pv210-nand":
0x0000000c0000-0x000000100000 : "misc"
0x000000100000-0x000000600000 : "recovery"
0x000000600000-0x000000b00000 : "kernel"
0x000000b00000-0x000000e00000 : "ramdisk"
0x000000e00000-0x000010000000 : "system"