移植linux-2.6.32.2到感知SensorRF2开发平台(实录)—— 杨学鹏
根据《Mini2440_Linux一直开发实战指南.pdf》的移植步骤,亲自对购买的开发平台进行了系统移植,下面是移植的全过程记录:
目录:
5,修改init/main.c文件(这一步为什么做,有待探究。不做串口无显示。) 3
1,下载linux-2.6.32.2源码并解压
怎么下,怎么解压不用我说了吧。很简单,linux本身的命令;
http://www.kernel.org/pub/linux/kernel/v2.6/
# tar zxvf linux-2.6.32.2.tar.gz
2,指定交叉编译链
# vi Makefile
将
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?=
改为
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-
如下图:
3,检验编译是否通过
执行编译命令,看能否编译通过,不必烧写到开发平台。
# make s3c2410_defconfig
# make
make时间比较长,请耐心等待。
4,修改机器码和时钟频率
删除arch/arm/mach-s3c2440/mach-mini2440.c:
# rm arch/arm/mach-s3c2440/mach-mini2440.c -f
拷贝arch/arm/mach-s3c2440/mach-smdk2440.c为mach-mini2440.c:
# cp arch/arm/mach-s3c2440/mach-smdk2440.c arch/arm/mach-s3c2440/mach-mini2440.c
# vi arch/arm/mach-s3c2440/mach-mini2440.c
①将
MACHINE_START(S3C2440, "SMDK2440")
修改为
MACHINE_START(MINI2440, "FriendlyARM Mini2440 development board")
如下图:
②将static void __init smdk2440_map_io(void)函数中的
s3c24xx_init_clocks(16934400);
改为
s3c24xx_init_clocks(12000000);
如下图:
③在mach-mini2440.c文件的冒号模式下执行如下命令:
:%s/smdk2440/mini2440/g
目的是将文中的smdk2440改成mini2440.
④屏蔽掉mini2440_machine_init(void)函数中的
smdk_machine_init();
因为我们自己要写。
5,修改init/main.c文件(这一步为什么做,有待探究。不做串口无显示。)
①第117行左右,增加如下代码:
char __initdata boot_command_line1[100] = "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC1,115200";
如下图:
②第521行左右,增加变量i。
如下图:
③第554行左右,增加如下代码:
printk(KERN_NOTICE "Kernel command line:222s\n");
printk(KERN_NOTICE "%s", command_line);
for (i=0; i<66; i++)
{
command_line[i] = boot_command_line1[i];
}
如下图:
④第571行左右,增加如下代码:
for (i=0; i<66; i++)
{
boot_command_line[i] = boot_command_line1[i];
}
如下图:
6,编译测试
# make mini2440_defconfig
# make zImage
可在arch/arm/boot下生成zImage文件,将它烧写到开发平台,运行,串口可输出如下信息:(见temp/串口输出信息1.txt)
7,移植NAND驱动并更改分区信息
# vi arch/arm/mach-s3c2440/mach-mini2440.c
①添加头文件。
// add by xuepeng
#include <linux/mtd/partitions.h>
#include <plat/nand.h>
如下图:
②添加static struct mtd_partition mini2440_default_nand_part[]
// add by xuepeng
static struct mtd_partition mini2440_default_nand_part[] = {
[0] = {
.name = "supervivi",
.size = 0x00040000,
.offset = 0,
},
[1] = {
.name = "param",
.offset = 0x00040000,
.size = 0x00020000,
},
[2] = {
.name = "Kernel",
.offset = 0x00060000,
.size = 0x00500000,
},
[3] = {
.name = "root",
.offset = 0x00560000,
.size = 1024 * 1024 * 1024, //
},
[4] = {
.name = "nand",
.offset = 0x00000000,
.size = 1024 * 1024 * 1024, //
}
};
如下图:
③添加static struct s3c2410_nand_set mini2440_nand_sets[]
// add by xuepeng
static struct s3c2410_nand_set mini2440_nand_sets[] = {
[0] = {
.name = "NAND",
.nr_chips = 1,
.nr_partitions = ARRAY_SIZE(mini2440_default_nand_part),
.partitions = mini2440_default_nand_part,
},
};
如下图:
④添加static struct s3c2410_platform_nand mini2440_nand_info
// add by xuepeng
static struct s3c2410_platform_nand mini2440_nand_info = {
.tacls = 20,
.twrph0 = 60,
.twrph1 = 20,
.nr_sets = ARRAY_SIZE(mini2440_nand_sets),
.sets = mini2440_nand_sets,
.ignore_unset_ecc = 1,
};
如下图:
⑤mini2440_devices[]中添加平台设备。
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_nand, // add by xuepeng
};
如下图:
⑥mini2440_machine_init(void)函数中,platform_add_devices函数前,添加:
// add by xuepeng
s3c_device_nand.dev.platform_data = &mini2440_nand_info;
如下图:
⑦编译测试。
可以看到串口输出信息。(见temp/串口输出信息2.txt)
(跟linux-2.6.35.4的移植不太一样啊!!!!!)
8,使内核支持yaffs2文件系统
①yaffs2源码。
②为内核打补丁。
# cd yaffs2
# ./patch-ker.sh c ../linux-2.6.32.2
如下图:
可以看到linux-2.6.32.2/fs目录下,多了yaffs2目录。
③配置内核。
# make menuconfig
File systems --->
[*] Miscellaneous filesystems --->
选上
<*> YAFFS2 file system support
如下图:
保存并退出。
④编译测试内核。
# make zImage
烧写到开发平台,此时如果开发平台之前烧有yaffs2文件系统,则串口输出信息如下:
(见temp/串口输出信息3.txt)
9,移植DM9000网卡驱动
》》》》》》》》》mach-mini2440.c文件中:
①添加头文件。
// add by xuepeng
#include <linux/dm9000.h>
如下图:
②添加MACH_MINI2440_DM9K_BASE宏定义。
// add by xuepeng
/* DM9000AEP 10/100 ethernet controller */
#define MACH_MINI2440_DM9K_BASE (S3C2410_CS4 + 0x300)
③添加static struct resource mini2440_dm9k_resource[]
// add by xuepeng
static struct resource mini2440_dm9k_resource[] = {
[0] = {
.start = MACH_MINI2440_DM9K_BASE,
.end = MACH_MINI2440_DM9K_BASE + 3,
.flags = IORESOURCE_MEM
},
[1] = {
.start = MACH_MINI2440_DM9K_BASE + 4,
.end = MACH_MINI2440_DM9K_BASE + 7,
.flags = IORESOURCE_MEM
},
[2] = {
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
④添加static struct dm9000_plat_data mini2440_dm9k_pdata
// add by xuepeng
/*
* * The DM9000 has no eeprom, and it's MAC address is set by
* * the bootloader before starting the kernel.
* */
static struct dm9000_plat_data mini2440_dm9k_pdata = {
.flags = (DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM),
};
⑤添加static struct platform_device mini2440_device_eth
// add by xuepeng
static struct platform_device mini2440_device_eth = {
.name = "dm9000",
.id = -1,
.num_resources = ARRAY_SIZE(mini2440_dm9k_resource),
.resource = mini2440_dm9k_resource,
.dev = {
.platform_data = &mini2440_dm9k_pdata,
},
};
如下图:
⑥mini2440_devices[]中添加平台设备。
&mini2440_device_eth, // add by xuepeng
如下图:
》》》》》》》》》drivers/net/dm9000.c文件中:
⑦添加头文件。
// add by xuepeng
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
如下图:
⑧修改dm9000_init函数。
函数开始处添加:
// add by xuepeng
#if defined(CONFIG_ARCH_S3C2410)
unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;
unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;
*((volatile unsigned int *)S3C2410_BWSCON) =
(oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
*((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
#endif
如下图:
⑨修改dm9000_probe函数。
if (!is_valid_ether_addr(ndev->dev_addr))前添加:(大约1464行)
// add by xuepeng
memcpy(ndev->dev_addr, "\x08\x90\x90\x90\x90\x90", 6);
如下图:
⑩配置编译内核。
Device Drivers --->
Network device support --->
Ethernet(10 or 100Mbit) --->
<*> DM9000 support
可见,Linux-2.6.32.2已经默认支持DM9000了。
# make zImage
烧写到开发板,运行ifconfig命令,检验是否有eth0信息。
A,没有移植DM9000之前:
B,移植DM9000之后:
此时的启动信息见/temp/串口输出信息3.txt
10,激活TRC驱动
Linux-2.6.32.2对2440的RTC驱动已经十分完善了,只需要将设备加入即可。
(修改arch/arm/mach-s3c2440/mach-mini2440.c)
①static struct platform_device *mini2440_devices[]中添加平台设备:
&s3c_device_rtc, // add by xuepeng
如下图:
②配置内核。
# make menuconfig
Device Drivers --->
<*> Real Time Clock --->
如下图:
可见,linux-2.6.32.2已经默认选择了RTC相关的选项。
这里需要特别注意的地方是最下方的<*> Sansung S3C series SoC RTC选项,因为这里才是内核中真正的2440的RTC驱动配置项。
③编译测试。
# make zImage
烧写到开发平台,输入如下命令测试:
# date -s 052617142012.00
# hwclock -w
A,加入RTC驱动前:
B,加入RTC驱动后:
另外,还可以通过查看/dev/下是否有rtc设备驱动:
11,添加背光驱动
①添加mini2440_backlight.c文件。
在drivers/video目录下添加一个mini2440_backlight.c的驱动文件。内容如下:
// 以下头文件可能并不是每一个必须的,但多余的并不会影响驱动程序的内容
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
#else
#define DPRINTK(x...) (void)(0)
#endif
// 定义背光驱动的名称为backlight,将会出现在/dev/backlight
#define DEVICE_NAME "backlight"
// 定义背光驱动变量bl_state,以记录背光的开关状态
static unsigned int bl_state;
// 设置背光开关的函数,主要是翻转背光变量bl_state
static inline void set_bl(int state)
{
bl_state = !!state; // 翻转bl_state变量
s3c2410_gpio_setpin(S3C2410_GPG(4), bl_state); // 把结果写入背光所用的寄存器GPG4
}
// 获取背光状态
static inline unsigned int get_bl(void)
{
return bl_state;
}
// 从应用程序读取参数,并传递到内核中
static ssize_t dev_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
{
unsigned char ch;
int ret;
if (count == 0) {
return count;
}
// 使用copy_from_user函数从用户层/应用层读取参数
ret = copy_from_user(&ch, buffer, sizeof ch) ? -EFAULT : 0;
if (ret) {
return ret;
}
ch &= 0x01; // 判断奇数还是偶数
set_bl(ch); // 设置背光状态
return count;
}
// 把内核参数传递给用户层/应用层的读函数
static ssize_t dev_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
int ret;
unsigned char str[] = {'0', '1' };
if (count == 0) {
return 0;
}
// 使用copy_to_user函数把内核参数传递到用户层/应用层
ret = copy_to_user(buffer, str + get_bl(), sizeof(unsigned char) ) ? -EFAULT : 0;
if (ret) {
return ret;
}
return sizeof(unsigned char);
}
// 设备操作集
static struct file_operations dev_fops = {
owner: THIS_MODULE,
read: dev_read,
write: dev_write,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
// 设备初始化,内核启动时就有效
static int __init dev_init(void)
{
int ret;
ret = misc_register(&misc);
printk (DEVICE_NAME"\tinitialized\n");
// 初始化背光所用的端口GPG4为输出
s3c2410_gpio_cfgpin(S3C2410_GPG(4), S3C2410_GPIO_OUTPUT);
// 启动内核时打开背光
set_bl(1);
return ret;
}
static void __exit dev_exit(void)
{
misc_deregister(&misc);
}
module_init(dev_init); // 注册背光驱动模块
module_exit(dev_exit); // 卸载背光驱动模块
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");
②把背光配置加入到内核配置菜单。
# vi drivers/video/Kconfig
在
config FB_S3C2410_DEBUG
和
config FB_SM501
之间,添加:
config BACKLIGHT_MINI2440
tristate "Backlight support for mini2440 from FriendlyARM"
depends on MACH_MINI2440 && FB_S3C2410
help
backlight driver for MINI2440 from FriendlyARM
如下图:
③在Makefile中,根据配置定义加入驱动目标文件。
# vi drivers/video/Makefile
在最后,添加:
obj-$(CONFIG_BACKLIGHT_MINI2440) += mini2440_backlight.o
如下图:
④配置内核。
# make menuconfig
Device Drivers --->
Graphics support --->
<*> Support for frame buffer devices --->
选上:
< > Backlight support for mini2440 from FriendlyARM
如下图:
保存、退出。
⑤编译、测试。
# make zImage
烧写到开发平台,并启动。可以看到屏幕有闪烁了。
进入命令行,输入命令测试:
# echo 0 > /dev/backlight 可以关闭LCD背光(发送偶数)
# echo 1 > /dev/backlight 可以打开LCD背光(发送奇数)
12,移植LCD显示驱动
①删除原先的LCD设备平台代码。
# vi arch/arm/mach-s3c2440/mach-mini2440.c
删掉以下代码:(大约200行左右)
/* LCD driver info */
static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
.type = S3C2410_LCDCON1_TFT,
.width = 240,
.height = 320,
.pixclock = 166667, /* HCLK 60 MHz, divisor 10 */
.xres = 240,
.yres = 320,
.bpp = 16,
.left_margin = 20,
.right_margin = 8,
.hsync_len = 4,
.upper_margin = 8,
.lower_margin = 7,
.vsync_len = 4,
};
static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
.displays = &mini2440_lcd_cfg,
.num_displays = 1,
.default_display = 0,
#if 0
/* currently setup by downloader */
.gpccon = 0xaa940659,
.gpccon_mask = 0xffffffff,
.gpcup = 0x0000ffff,
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaa84aaa0,
.gpdcon_mask = 0xffffffff,
.gpdup = 0x0000faff,
.gpdup_mask = 0xffffffff,
#endif
.lpcsel = ((0xCE6) & ~7) | 1<<4,
};
②增加新LCD代码
代码如下:
// add by xuepneg
/* LCD driver info */
// NEC 3.5"的配置和参数设置
#if defined(CONFIG_FB_S3C2410_N240320)
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXCLOCK 100000
#define LCD_RIGHT_MARGIN 36
#define LCD_LEFT_MARGIN 19
#define LCD_HSYNC_LEN 5
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1
// 夏普 8"的配置和参数设置
#elif defined(CONFIG_FB_S3C2410_TFT640480)
#define LCD_WIDTH 640
#define LCD_HEIGHT 480
#define LCD_PIXCLOCK 80000
#define LCD_RIGHT_MARGIN 67
#define LCD_LEFT_MARGIN 40
#define LCD_HSYNC_LEN 31
#define LCD_UPPER_MARGIN 25
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1
// 统宝 3.5"的配置和参数设置
#elif defined(CONFIG_FB_S3C2410_T240320)
#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXCLOCK 146250 // 170000
#define LCD_RIGHT_MARGIN 25
#define LCD_LEFT_MARGIN 0
#define LCD_HSYNC_LEN 4
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 4
#define LCD_VSYNC_LEN 1
// 群创 7"的配置和参数设置
#elif defined(CONFIG_FB_S3C2410_TFT800480)
#define LCD_WIDTH 800
#define LCD_HEIGHT 480
#define LCD_PIXCLOCK 11463 // 40000
#define LCD_RIGHT_MARGIN 67
#define LCD_LEFT_MARGIN 40
#define LCD_HSYNC_LEN 31
#define LCD_UPPER_MARGIN 25
#define LCD_LOWER_MARGIN 5
#define LCD_VSYNC_LEN 1
// LCD2VGA(分辨率为1024x768)模块的配置和参数设置
#elif defined(CONFIG_FB_S3C2410_VGA1024768)
#define LCD_WIDTH 1024
#define LCD_HEIGHT 768
#define LCD_PIXCLOCK 80000
#define LCD_RIGHT_MARGIN 15
#define LCD_LEFT_MARGIN 199
#define LCD_HSYNC_LEN 15
#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 1
#define LCD_VSYNC_LEN 1
#define LCD_CON5 (S3C2410_LCDCON5_FRM565 | S3C2410_LCDCON5_HWSWP)
#endif
// add by xuepeng
#if defined (LCD_WIDTH)
static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {
#if !defined (LCD_CON5)
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
#else
.lcdcon5 = LCD_CON5,
#endif
.type = S3C2410_LCDCON1_TFT,
.width = LCD_WIDTH,
.height = LCD_HEIGHT,
.pixclock = LCD_PIXCLOCK,
.xres = LCD_WIDTH,
.yres = LCD_HEIGHT,
.bpp = 16,
.left_margin = LCD_LEFT_MARGIN + 1,
.right_margin = LCD_RIGHT_MARGIN + 1,
.hsync_len = LCD_HSYNC_LEN + 1,
.upper_margin = LCD_UPPER_MARGIN + 1,
.lower_margin = LCD_LOWER_MARGIN + 1,
.vsync_len = LCD_VSYNC_LEN + 1,
};
// add by xuepeng
static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
.displays = &mini2440_lcd_cfg,
.num_displays = 1,
.default_display = 0,
.gpccon = 0xaa955609,
.gpccon_mask = 0xffc003cc,
.gpcup = 0x0000ffff,
.gpcup_mask = 0xffffffff,
.gpdcon = 0xaa95aaa1,
.gpdcon_mask = 0xffc0fff0,
.gpdup = 0x0000faff,
.gpdup_mask = 0xffffffff,
.lpcsel = 0xf82,
};
#endif
③修改mini2440_machine_init函数。
mini2440_machine_init函数中,将
s3c24xx_fb_set_platdata(&mini2440_fb_info);
改为:
#if defined (LCDD_WIDTH)
s3c24xx_fb_set_platdata(&mini2440_fb_info);
#endif
如下图:
④增加配置选项。
# vi drivers/video/Kconfig
1930行左右添加:
# add by xuepeng
choice
prompt "LCD select"
depends on FB_S3C2410
help
S3C24x0 LCD size select
config FB_S3C2410_T240320
boolean "3.5 inch 240X320 Toppoly LCD"
depends on FB_S3C2410
help
3.5 inch 240X320 Toppoly LCD
config FB_S3C2410_N240320
boolean "3.5 inch 240X320 NEC LCD"
depends on FB_S3C2410
help
3.5 inch 240x320 NEC LCD
config FB_S3C2410_TFT640480
boolean "8 inch 640X480 L80 LCD"
depends on FB_S3C2410
help
8 inch 640X480 LCD
config FB_S3C2410_TFT800480
boolean "7 inch 800x480 TFT LCD"
depends on FB_S3C2410
help
7 inch 800x480 TFT LCD
config FB_S3C2410_VGA1024768
boolean "VGA 1024x768"
depends on FB_S3C2410
help
VGA 1024x768
endchoice
如下图:
……
⑤修改drivers/video/s3c2410_fb.c文件。(为什么修改?有待探讨!!!!!!!)
# vi drivers/video/s3c2410_fb.c
在688行左右,s3c2410fb_init_registers函数中,添加变量:
unsigned long tmp; // add by xuepeng
在709行左右,添加:
// add by xuepeng
tmp = readl(S3C2410_GPCCON) & 0xFFFFFF0F;
tmp = tmp | 0x00000050;
writel(tmp , S3C2410_GPCCON);
// add by xuepeng
tmp = readl(S3C2410_GPCDAT) & 0xFFF3;
writel(tmp , S3C2410_GPCDAT);
⑥配置内核
# make menuconfig
Device Drivers --->
Graphics support --->
<*> Support for frame buffer devices --->
LCD select (3.5 inch 240X320 Toppoly LCD) --->
选中:
( ) 7 inch 800x480 FTF LCD
保存、退出。
⑦编译、测试。
# make zImage
将zImage烧写到开发平台,并启动。
可以看到一个可爱的小企鹅在屏幕的左上方。O(∩_∩)o
13,修改Linux Logo
开机logo对应文件是:drivers/video/logo/logo_linux_clut224.ppm
①使用LogoMaker制作Linux LOGO.
Ø LogoMaker的安装:
A,官网下载LogoMaker;
B,执行命令:
# tar zxvf logomaker.tgz -C /
执行以上命令,LogoMaker将会安装到/usr/sbin目录下。
Ø LogoMaker的使用:
A,终端下运行命令:
# logomaker
即可启动LogoMaker。
B,打开一张图片。
注意打开图片的大小!!!!!
C,转换并保存。
点击File->Convert the picture to a Linux Logo File,会打开如下对话框:
点击“打开”即可。(此处应该是“保存”,软件有缺陷!)
此时,就会自动生成一个logo_linux_clut224.ppm文件。
②覆盖源码文件。
将生成的logo_linux_clut224.ppm文件,替换掉drivers/video/logo/logo_linux_clut224.ppm即可。
③编译、测试。
# make zImage
烧写到开发平台,开机。会发现开机Logo已经换成了我们刚才制作的那个了。
14,添加ADC驱动
需要解决ADC和触摸屏共享资源问题。
①添加驱动文件
drivers/char/下建立文件:mini2440_adc.c,内容如下:
// add by xuepeng
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>
#include <mach/regs-gpio.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
//自己定义的头文件,因原生内核并没有包含
#include "s3c24xx-adc.h"
#undef DEBUG
//#define DEBUG
#ifdef DEBUG
#define DPRINTK(x...) {printk(__FUNCTION__"(%d): ",__LINE__);printk(##x);}
#else
#define DPRINTK(x...) (void)(0)
#endif
// 定义ADC转换设备名称,将出现在/dev/adc
#define DEVICE_NAME "adc"
static void __iomem *base_addr;
// 定义ADC设备结构
typedef struct {
wait_queue_head_t wait;
int channel;
int prescale;
}ADC_DEV;
// 声明全局信号量,以便和触摸屏驱动程序共享A/D转换器
DECLARE_MUTEX(ADC_LOCK);
// ADC驱动是否拥有A/D转换器资源的状态变量
static int OwnADC = 0;
static ADC_DEV adcdev;
static volatile int ev_adc = 0;
static int adc_data;
static struct clk *adc_clock;
// 定义ADC相关的寄存器
#define ADCCON (*(volatile unsigned long *)(base_addr + S3C2410_ADCCON)) //ADC control
#define ADCTSC (*(volatile unsigned long *)(base_addr + S3C2410_ADCTSC)) //ADC touch screen control
#define ADCDLY (*(volatile unsigned long *)(base_addr + S3C2410_ADCDLY)) //ADC start or Interval Delay
#define ADCDAT0 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT0)) //ADC conversion data 0
#define ADCDAT1 (*(volatile unsigned long *)(base_addr + S3C2410_ADCDAT1)) //ADC conversion data 1
#define ADCUPDN (*(volatile unsigned long *)(base_addr + 0x14)) //Stylus Up/Down interrupt status
#define PRESCALE_DIS (0 << 14)
#define PRESCALE_EN (1 << 14)
#define PRSCVL(x) ((x) << 6)
#define ADC_INPUT(x) ((x) << 3)
#define ADC_START (1 << 0)
#define ADC_ENDCVT (1 << 15)
// 定义“开启AD输入”宏,因为比较简单,故没有做成函数
#define START_ADC_AIN(ch, prescale) \
do{ \
ADCCON = PRESCALE_EN | PRSCVL(prescale) | ADC_INPUT((ch)) ; \
ADCCON |= ADC_START; \
}while(0)
// ADC中断处理函数
static irqreturn_t adcdone_int_handler(int irq, void *dev_id)
{
// 如果ADC驱动拥有“A/D转换器”资源,则从ADC寄存器读取转换结果
if (OwnADC) {
adc_data = ADCDAT0 & 0x3ff;
ev_adc = 1;
wake_up_interruptible(&adcdev.wait);
}
return IRQ_HANDLED;
}
// ADC读函数,一般对应于用户层/应用层的设备读函数(read)
static ssize_t s3c2410_adc_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)
{
char str[20];
int value;
size_t len;
// 判断“A/D转换器”资源是否可用
if (down_trylock(&ADC_LOCK) == 0) {
OwnADC = 1; // 标记“A/D转换器”资源状态为可用
START_ADC_AIN(adcdev.channel, adcdev.prescale); // 开始转换
wait_event_interruptible(adcdev.wait, ev_adc); // 通过终端的方式等待转换结果
ev_adc = 0;
DPRINTK("AIN[%d] = 0x%04x, %d\n", adcdev.channel, adc_data, ADCCON & 0x80 ? 1:0);
// 把转换结果赋予value,以便传递到用户层/应用层
value = adc_data;
// 释放“A/D转换器”资源
OwnADC = 0;
up(&ADC_LOCK);
} else {
// 没有“A/D转换器”资源,赋值为“-1”
value = -1;
}
len = sprintf(str, "%d\n", value);
if (count >= len) {
// 把转换结果传递到用户层/应用层
int r = copy_to_user(buffer, str, len);
return r ? r : len;
} else {
return -EINVAL;
}
}
// 打开ADC设备的函数,一般对应于用户态程序的open
static int s3c2410_adc_open(struct inode *inode, struct file *filp)
{
// 初始化中断队列
init_waitqueue_head(&(adcdev.wait));
// 缺省通道为“0”
adcdev.channel=0;
adcdev.prescale=0xff;
DPRINTK( "adc opened\n");
return 0;
}
static int s3c2410_adc_release(struct inode *inode, struct file *filp)
{
DPRINTK( "adc closed\n");
return 0;
}
static struct file_operations dev_fops = {
owner: THIS_MODULE,
open: s3c2410_adc_open,
read: s3c2410_adc_read,
release: s3c2410_adc_release,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static int __init dev_init(void)
{
int ret;
base_addr=ioremap(S3C2410_PA_ADC,0x20);
if (base_addr == NULL) {
printk(KERN_ERR "Failed to remap register block\n");
return -ENOMEM;
}
adc_clock = clk_get(NULL, "adc");
if (!adc_clock) {
printk(KERN_ERR "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clock);
/* normal ADC */
ADCTSC = 0;
// 注册中断
ret = request_irq(IRQ_ADC, adcdone_int_handler, IRQF_SHARED, DEVICE_NAME, &adcdev);
if (ret) {
iounmap(base_addr);
return ret;
}
// 注册设备
ret = misc_register(&misc);
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
static void __exit dev_exit(void)
{
// 释放中断
free_irq(IRQ_ADC, &adcdev);
iounmap(base_addr);
if (adc_clock) {
clk_disable(adc_clock);
clk_put(adc_clock);
adc_clock = NULL;
}
misc_deregister(&misc);
}
// 导出信号量“ADC_LOCK”,以便触摸屏驱动使用
EXPORT_SYMBOL(ADC_LOCK);
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("FriendlyARM Inc.");
②添加头文件。
drivers/char/下新建文件:s3c24xx-adc.h,内容如下:
#ifndef _S3C2410_ADC_H_
#define _S3C2410_ADC_H_
#define ADC_WRITE(ch, prescale) ((ch)<<16|(prescale))
#define ADC_WRITE_GETCH(data) (((data)>>16)&0x7)
#define ADC_WRITE_GETPRE(data) ((data)&0xff)
#endif /* _S3C2410_ADC_H_ */
③修改Makefile文件。
# vi drivers/char/Makefile
114行左右,添加:
Obj-$(CONFIG_MINI2440_ADC) += mini2440_adc.o
如下图:
④添加配置选项。
# vi drivers/char/Kconfig
100行左右,添加:
# add by xuepeng
config MINI2440_ADC
bool "ADC driver for FriendlyARM Mini2440 development boards"
depends on MACH_MINI2440
default y if MACH_MINI2440
help
this is ADC driver for FriendlyARM Mini2440 development boards
Nots:the touch-screen-driver required this option
如下图:
⑤配置内核。
# make menuconfig
Device Drivers --->
Character devices --->
选上:
[*] ADC driver for FriendlyARM Mini2440 development boards (NEW)
如下图:
⑥编译、测试内核。
# make zImage
烧写进开发平台,编写测试程序如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <errno.h>
#include <string.h>
int main(void)
{
fprintf(stderr, "press Ctrl-C to stop\n");
int fd = open("/dev/adc", 0);
if (fd<0)
{
perror("open ADC device:");
return 1;
}
for(;;)
{
char buffer[30];
int len = read(fd, buffer, sizeof(buffer)-1);
if (len >0)
{
buffer[len] = '\0';
int value = -1;
sscanf(buffer, "%d", &value);
}
else
{
perror("read ADC device:");
return 1;
}
usleep(500*1000);
}
close(fd);
}
据《Mini2440_Linux移植开发实战指南》:
运行test_adc,旋转开发板上的 W1可调电阻,可以看到 ADC转换的结果也在变动,按下触摸屏时,会输出“-1 ”,这和我们在驱动程序中设置的结果是一样的,如图:
但是我们怎么没有任何反应呢?可能是A/D的线路连接方式不一样?还是有的驱动还未移植啊?不懂!稍后再说。
15,添加触摸屏驱动
触摸屏的原理有待加强!
①添加驱动文件。
drivers/input/touchscreen下新建文件s3c2410_ts.c,内容如下:
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/gpio.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <plat/regs-adc.h>
#include <mach/regs-gpio.h>
/* For ts.dev.id.version */
#define S3C2410TSVERSION 0x0101
#define WAIT4INT(x) (((x)<<8) | \
S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
S3C2410_ADCTSC_XY_PST(3))
#define AUTOPST (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
static char *s3c2410ts_name = "s3c2410 TouchScreen";
static struct input_dev *dev;
static long xp;
static long yp;
static int count;
extern struct semaphore ADC_LOCK;
static int OwnADC = 0;
static void __iomem *base_addr;
static inline void s3c2410_ts_connect(void)
{
s3c2410_gpio_cfgpin(S3C2410_GPG(12), S3C2410_GPG12_XMON);
s3c2410_gpio_cfgpin(S3C2410_GPG(13), S3C2410_GPG13_nXPON);
s3c2410_gpio_cfgpin(S3C2410_GPG(14), S3C2410_GPG14_YMON);
s3c2410_gpio_cfgpin(S3C2410_GPG(15), S3C2410_GPG15_nYPON);
}
static void touch_timer_fire(unsigned long data)
{
unsigned long data0;
unsigned long data1;
int updown;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) {
if (count != 0) {
long tmp;
tmp = xp;
xp = yp;
yp = tmp;
xp >>= 2;
yp >>= 2;
input_report_abs(dev, ABS_X, xp);
input_report_abs(dev, ABS_Y, yp);
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_PRESSURE, 1);
input_sync(dev);
}
xp = 0;
yp = 0;
count = 0;
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else {
count = 0;
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
if (OwnADC) {
OwnADC = 0;
up(&ADC_LOCK);
}
}
}
static struct timer_list touch_timer =
TIMER_INITIALIZER(touch_timer_fire, 0, 0);
static irqreturn_t stylus_updown(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
int updown;
if (down_trylock(&ADC_LOCK) == 0) {
OwnADC = 1;
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
if (updown) {
touch_timer_fire(0);
} else {
OwnADC = 0;
up(&ADC_LOCK);
}
}
return IRQ_HANDLED;
}
static irqreturn_t stylus_action(int irq, void *dev_id)
{
unsigned long data0;
unsigned long data1;
if (OwnADC) {
data0 = ioread32(base_addr+S3C2410_ADCDAT0);
data1 = ioread32(base_addr+S3C2410_ADCDAT1);
xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
count++;
if (count < (1<<2)) {
iowrite32(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST, base_addr+S3C2410_ADCTSC);
iowrite32(ioread32(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_ENABLE_START, base_addr+S3C2410_ADCCON);
} else {
mod_timer(&touch_timer, jiffies+1);
iowrite32(WAIT4INT(1), base_addr+S3C2410_ADCTSC);
}
}
return IRQ_HANDLED;
}
static struct clk *adc_clock;
static int __init s3c2410ts_init(void)
{
struct input_dev *input_dev;
adc_clock = clk_get(NULL, "adc");
if (!adc_clock) {
printk(KERN_ERR "failed to get adc clock source\n");
return -ENOENT;
}
clk_enable(adc_clock);
base_addr=ioremap(S3C2410_PA_ADC,0x20);
if (base_addr == NULL) {
printk(KERN_ERR "Failed to remap register block\n");
return -ENOMEM;
}
/* Configure GPIOs */
s3c2410_ts_connect();
iowrite32(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(0xFF),\
base_addr+S3C2410_ADCCON);
iowrite32(0xffff, base_addr+S3C2410_ADCDLY);
iowrite32(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
/* Initialise input stuff */
input_dev = input_allocate_device();
if (!input_dev) {
printk(KERN_ERR "Unable to allocate the input device !!\n");
return -ENOMEM;
}
dev = input_dev;
dev->evbit[0] = BIT(EV_SYN) | BIT(EV_KEY) | BIT(EV_ABS);
dev->keybit[BITS_TO_LONGS(BTN_TOUCH)] = BIT(BTN_TOUCH);
input_set_abs_params(dev, ABS_X, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_Y, 0, 0x3FF, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, 0, 1, 0, 0);
dev->name = s3c2410ts_name;
dev->id.bustype = BUS_RS232;
dev->id.vendor = 0xDEAD;
dev->id.product = 0xBEEF;
dev->id.version = S3C2410TSVERSION;
/* Get irqs */
if (request_irq(IRQ_ADC, stylus_action, IRQF_SHARED|IRQF_SAMPLE_RANDOM,
"s3c2410_action", dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_ADC !\n");
iounmap(base_addr);
return -EIO;
}
if (request_irq(IRQ_TC, stylus_updown, IRQF_SAMPLE_RANDOM,
"s3c2410_action", dev)) {
printk(KERN_ERR "s3c2410_ts.c: Could not allocate ts IRQ_TC !\n");
iounmap(base_addr);
return -EIO;
}
printk(KERN_INFO "%s successfully loaded\n", s3c2410ts_name);
/* All went ok, so register to the input system */
input_register_device(dev);
return 0;
}
static void __exit s3c2410ts_exit(void)
{
disable_irq(IRQ_ADC);
disable_irq(IRQ_TC);
free_irq(IRQ_TC,dev);
free_irq(IRQ_ADC,dev);
if (adc_clock) {
clk_disable(adc_clock);
clk_put(adc_clock);
adc_clock = NULL;
}
input_unregister_device(dev);
iounmap(base_addr);
}
module_init(s3c2410ts_init);
module_exit(s3c2410ts_exit);
②修改Makefile文件。
# vi drivers/input/touchscreen/Makefile
在最后,添加:
obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
如下图:
③添加配置选项。
# vi drivers/input/touchscreen/Kconfig
添加:
config TOUCHSCREEN_S3C2410
tristate "Samsung S3C2410 touchscreen input driver"
depends on MACH_MINI2440 && INPUT && INPUT_TOUCHSCREEN && MINI2440_ADC
help
Say Y here if you have the s3c2410 touchscreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called s3c2410_ts.
如下图:
④配置内核。
# make menuconfig
Device Drivers --->
Input device support --->
[*] Touchscreens --->
选上:
<*> Samsung S3C2410 touchscreen input driver (NEW)
如下图:
保存、退出。
⑤编译、测试。
# make zImage
烧写到开发平台。启动开发平台,会进入调整触摸屏的界面:
成功啦。
16,配置USB外设
①配置和测试USB键盘、扫描器和鼠标。
对应内核代码为:drivers/hid/usbhid
Ø 配置:
# make menuconfig
Device Drivers --->
[*] HID Devices --->
选上:
<*> USB Human Interface Device (full HID) support
如下图:
Ø 测试:
# make zImage
烧写入开发平台,插入USB鼠标和键盘即可测试。
②配置测试优盘。
Ø 配置:
# make menuconfig
Device Drivers --->
SCSI device support --->
选上:
<*> SCSI device support
和
<*> SCSI disk support
如下图:
返回Device Drivers菜单,选择
[*] USB support --->
选上:
<*> USB Mass Storage support
如下图:
返回配置主界面,选择:
File systems --->
DOS/FAT/NT Filesystems --->
选上:
<*> MSDOS fs support
返回File systems菜单,选择:
_*_ Native language support --->
选上:
<*> Codepage 437 (United States, Canada)
和
<*> NLS ISO 8859-1 (Latin 1;Western European Languages)
和
<*> NLS UTF-8
如下图:
Ø 测试:
# make zImage
烧写进开发平台,启动开发平台。
待启动完毕后插入优盘,会在控制终端中输出以下信息:
③配置和测试USB摄像头
Ø 配置:
# make menuconfig
Device Drivers --->
选上:
<*> Multimedia support --->
选上:
<*> Video For Linux
进入:
[*] Video capture adapters (NEW) --->
[*] V4L USB devices (NEW) --->
选上并进入:
<*> GSPCA based webcams --->
选择所有(如下图):
说明:GSPCA是一个法国程序员写的万能USB摄像头驱动程序。
Ø 测试:(未测试)
# make zImage
烧写进开发平台,启动,插入USB摄像头,打开root_qtopia文件系统带的USB摄像头预览程序进行测试。
④配置和测试USB无线网卡
Ø 配置:
# make menuconfig
n 添加无线网络协议。
[*] Netwoking support --->
[*] Wireless --->
选上:
<*> cfg80211 - wireless configuration API
和
<*> Generic IEEE 802.11 Networking Stack (mac80211)
如下图:
n 配置无线网卡驱动。
退回到配置主界面。
Device Drivers --->
[*] Network device support --->
[*] Wireless LAN --->
[*] Wireless LAN (IEEE 802.11) --->
我全部选上了。(如下图)
Ø 测试:
# make zImage
烧写进开发平台,启动。
但是,插入USB无线网卡后,并没有启动无线网络连接。没有eth1。有待追究!!!
17,移植SD卡驱动
Linux-2.6.32.2已经自带了s3c2440芯片的SD卡驱动,我们只需在初始化代码中加入SD平台设备结构即可。
# vi arch/arm/mach-s3c2440/mach-mini2440.c
①添加头文件。
#include <linux/mmc/host.h>
#include <plat/mci.h>
如下图:
②添加static struct s3c24xx_mci_pdata mini2440_mmc_cfg结构体。
/* MMC/SD */
static struct s3c24xx_mci_pdata mini2440_mmc_cfg = {
.gpio_detect = S3C2410_GPG(8),
.gpio_wprotect = S3C2410_GPH(8),
.set_power = NULL,
.ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34,
};
如下图:
③加入到目标平台设备结构体。
&s3c_device_sdi,
如下图:
④修改drivers/mmc/host/s3cmci.c文件。
SD 卡的驱动程序底层操作实际对应源代码linux-2.6.32.2/drivers/mmc/host/s3cmci.c ,
根据测试,当包含内核打印信息时,SD 卡可以被正常识别使用,而没有打印信息时,则表现
的不太稳定,因此我们在该程序中添加了一句延时代码。如下图:
⑤编译、测试。
# make zImage
因为没有SD卡,所以没有进行测试。
18,移植UDA1341音频驱动
# vi arch/arm/mach-s3c2440/mach-mini2440.c
①添加头文件。
# include <sound/s3c24xx_usa134x.h>
如下图:
②添加static struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data结构体。
static struct s3c24xx_uda134x_platform_data s3c24xx_uda134x_data = {
.l3_clk = S3C2410_GPB(4),
.l3_data = S3C2410_GPB(3),
.l3_mode = S3C2410_GPB(2),
.model = UDA134X_UDA1341,
};
③添加static struct platform_device s3c24xx_uda134x结构体。
static struct platform_device s3c24xx_uda134x = {
.name = "s3c24xx_uda134x",
.dev = {
.platform_data = &s3c24xx_uda134x_data,
}
};
如下图:
④添加UDA134设备平台到内核。
&s3c24xx_uda134x,
如下图:
⑤配置内核。
# make menuconfig
Device Drivers --->
<*> Sound card support --->
选上:
[*] Preclaim OSS device numbers
进入
<*> Advanced Linux Sound Architecture --->
选择OSS结构相关的配置选项。
进入
<*> ALSA for SoC audio support --->
选上:
_*_ SoC I2C Audio support UDA134X wired to a S3C24XX
如下图:
保存、退出。
⑥编译、测试。
# make zImage
烧写进开发平台。启动。打开root_qtopia文件系统下的madplay播放一首歌曲,把耳机插入插孔测试。
(有待测试!!!)
19,休整串口驱动
①修改arch/arm/mach-s3c2440/mach-mini2440.c。
# vi arch/arm/mach-s3c2440/mach-mini2440.c
将mini2440_uartcfgs[]中的
[2] = {
……
.ulcon = 0x43,
……
}
改为:
[2] = {
……
.ulcon = 0x03,
……
}
如下图:
②修改drivers/serial/samsung.c文件。
# vi drivers/serial/samsung.c
添加头文件:
#include <linux/gpio.h>
#include <mach/regs-gpio.h>
如下图:
s3c24xx_serial_startup函数中,437行左右添加:
if (port->line == 2) {
s3c2410_gpio_cfgpin(S3C2410_GPH(6), S3C2410_GPH6_TXD2);
s3c2410_gpio_pullup(S3C2410_GPH(6), 1);
s3c2410_gpio_cfgpin(S3C2410_GPH(7), S3C2410_GPH7_RXD2);
s3c2410_gpio_pullup(S3C2410_GPH(7), 1);
}
如下图:
③编译、测试。
# make zImage
测试是通过文件系统带的串口助手程序实现的,不过需要用到三针串口线将开发板和电脑相连。(有待测试)
20,移植I2C-EEPROM驱动
Linux-2.6.32.2对s3c2440的I2C接口提供了完善的驱动,因此只需要配置一下即可。
①配置内核。
# make menuconfig
Device Drivers --->
<*> I2C support --->
I2C Hardware Bus support --->
选上:
<*> S3C2410 I2C Driver
如下图:
可见,内核已经默认选择上了。
②编译、测试。
# make zImage
烧写进开发平台,启动。
在超级终端中输入“i2c -w”即可测试,结果如下:
说明:本开发平台基于I2C总线挂接了一个EEPROM芯片(AT24C08),可通过它进行测试。
i2c的测试程序就是向板子的24C08器件写入数据(0x00-0xff)。
21,移植看门狗驱动
Linux-2.6.32.2内核已经具有完善的S3C2440的看门狗驱动了,我们只需要配置即可。
①配置内核。
# make menuconfig
Device Drivers --->
[*] Watchdog Timer Support --->
内核已经默认选择好了,如下:
对应的驱动源文件是:drivers/watchdog/s3c2410_wdt.c。
②编译、测试。
# make zImage
烧写进开发平台,超级终端执行如下命令:
开启看门狗,(随便写入一些数据即可):
# echo 0 > /dev/watchdog
如下图:
等待15s,系统将会重启,证明看门狗已经被启动了。
待开发平台重新启动后,重新输入命令:
# echo 0 > /dev/watchdog
接着输入:
# echo -n V > /dev/watchdog
这里,-n的作用是去掉回车。
再等超过15s,可以看见系统仍然正常运行,证明看门狗已经被关闭了。