一、需求分析:
二、驱动移植
2.1驱动分析:
2.2 修改驱动
三、驱动移植中遇到的问题和解决方法
3.1 发现问题
3.2 问题分析
一、需求分析:
以前二代相机使用的RTC芯片是isl12026,为提高精确度使用ds3231。Ds3231的精确度是isl12026的十倍~~
二、驱动移植
2.1驱动分析:
现在使用的内核版本是2.6.34没有ds3231驱动的支持。查找3.3内核有ds3232的驱动。
对比了两款芯片的差异。Ds3232只是多出两个寄存器和一个sram控制,配置接口都是使用I2C接口,可以使用ds3232驱动。
2.2 修改驱动
把3.3内核文件/driver/rtc/rtc-ds3232.c 复制到/driver/rtc/rtc-ds3232.c。
A. 修改/driver/rtc/Kconfig,
在config RTC_DRV_DS1672下面添加如下内容:
config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232"
depends on RTC_CLASS && I2C
help
If you say yes here you get support for Dallas Semiconductor
DS3232 real-time clock chips. If an interrupt is associated
with the device, the alarm functionality is supported.
This driver can also be built as a module. If so, the module
will be called rtc-ds3232.
B.修改/driver/rtc/Makefie 添加驱动文件:
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o 注意CONFIG_RTC_DRV_DS3232一定要和Kconfig 中的RTC_DRV_DS3232相匹配。
C.修改板级配置文件/arch/arm/mach-davinci/ board-dm365-evm.c
修改前:
static struct i2c_board_info i2c_info[] = {
{
I2C_BOARD_INFO("dm365evm_keys", 0x25),
},
{
I2C_BOARD_INFO("24c256", 0x50),
.platform_data = &eeprom_info,
},
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
},
{
I2C_BOARD_INFO("ths7303", 0x2c),
},
{
I2C_BOARD_INFO("PCA9543A", 0x73),
},
{
I2C_BOARD_INFO("isl12026", 0x6f),
},
{
I2C_BOARD_INFO("fs8816", 0x62),
},
};
修改后:
static struct i2c_board_info i2c_info[] = {
{
I2C_BOARD_INFO("dm365evm_keys", 0x25),
},
{
I2C_BOARD_INFO("24c256", 0x50),
.platform_data = &eeprom_info,
},
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
},
{
I2C_BOARD_INFO("ths7303", 0x2c),
},
{
I2C_BOARD_INFO("PCA9543A", 0x73),
},
{
I2C_BOARD_INFO("rtc-ds3232", 0x68),/*68(34) add for ds3231 RTC */
},
{
I2C_BOARD_INFO("fs8816", 0x62),
},
};
0x68为ds3231的I2C器件地址,在ds3231 datasheet中I2C地址为1101 0000(即0xD0),但在驱动中向右平移了一位变为0110 1000(即0x68)。
修改这个信息是告诉I2C控制器,slave 器件的I2C地址更改为0x68,slave器件的驱动名称是rtc-ds3232,这个驱动名称是关键,因为在设备和驱动匹配(probe)的时候会用到。
D.修改rtc-ds3232.c (R460行数)驱动文件
修改前:
static const struct i2c_device_id ds3232_id[] = {
{ " ds3232", 0 },
{ }
};
static const struct i2c_device_id ds3232_id[] = {
{ "rtc-ds3232", 0 },/*rtc-ds3232(ds3232) */
{ }
};
三、驱动移植中遇到的问题和解决方法
首先我先修改了
A.修改/driver/rtc/Kconfig
B.修改/driver/rtc/Makefie
C.修改板级配置文件/arch/arm/mach-davinci/ board-dm365-evm.c
这三个地方是大多驱动移植需要修改的,当时就希望修改这三个地方驱动就能移植成功~~ (当然没那么简单)。
修改这三处后就更新内核测试后就发现有问题了~~~~~~~~~~~~
3.1 发现问题
DM368跟换RTC芯片ds3231后会从终端打印找不到设备信息,具体信息如下:
NTP primary_loop Listening...
hwclock: can't open '/dev/misc/rtc': No such file or directory
set time to 1377108475.046875
25567 00008.561 7764.0 0.0 1377079666489554.0 1015625.0 0
无法找到/dev/misc/rtc' 设备。因为hwclock 是busybox 提供的一个设置RTC时钟的精简命令,所以参看busybox源码。在libbb/rtc.c中有这样一个函数调用:
int FAST_FUNC rtc_xopen(const char **default_rtc, int flags)
{
int rtc;
if (!*default_rtc) {
*default_rtc = "/dev/rtc";
rtc = open(*default_rtc, flags);
if (rtc >= 0)
return rtc;
*default_rtc = "/dev/rtc0";
rtc = open(*default_rtc, flags);
if (rtc >= 0)
return rtc;
*default_rtc = "/dev/misc/rtc";
}
return xopen(*default_rtc, flags);
}
从代码可知busybox查找RTC设备顺序为rtc ->rtc0 ->misc/rtc。
由此可知时钟器件有问题,根本没有相应的设备节点生成。
对比以前/dev下的设备列表,对比过程如下:
异常时:
# ls /dev
NULL mmcblk0p1 network_latency tty3
cfpga mtd0 network_throughput ttyS0
cmem mtd0ro null ttyS1
console mtd1 pcmC0D0c ttyp0
controlC0 mtd1ro pcmC0D0p ttyp1
cpu_dma_latency mtd2 ptmx ttyp2
davinci_previewer mtd2ro pts uart1_select
davinci_resizer mtd3 ptyp0 upgrateFPGA
dm365_aew mtd3ro ptyp1 upgrate_mcu
dm365_af mtd4 ptyp2 urandom
edma mtd4ro ram0 usbdev1.1
fb0 mtd5 random vcs
fb1 mtd5ro reset_fs8816 vcs1
fs8816 mtd6 reset_power vcsa
full mtd6ro resize_type vcsa1
i2c-1 mtdblock0 spi_cs video0
irqk mtdblock1 spi_slave_dev1 video2
kmem mtdblock2 timer video3
kmsg mtdblock3 tty watchdog
log mtdblock4 tty0 zero
mem mtdblock5 tty1
mmcblk0 mtdblock6 tty2
使用isl12026时的信息为:
# ls /dev
NULL mmcblk0p1 network_latency tty2
cfpga mtd0 network_throughput tty3
cmem mtd0ro null ttyS0
console mtd1 pcmC0D0c ttyS1
controlC0 mtd1ro pcmC0D0p ttyp0
cpu_dma_latency mtd2 ptmx ttyp1
davinci_previewer mtd2ro pts ttyp2
davinci_resizer mtd3 ptyp0 uart1_select
dm365_aew mtd3ro ptyp1 upgrateFPGA
dm365_af mtd4 ptyp2 upgrate_mcu
edma mtd4ro ram0 urandom
fb0 mtd5 random usbdev1.1
fb1 mtd5ro reset_fs8816 vcs
fs8816 mtd6 reset_power vcs1
full mtd6ro resize_type vcsa
i2c-1 mtdblock0 rtc0 vcsa1
irqk mtdblock1 spi_cs video0
kmem mtdblock2 spi_slave_dev1 video2
kmsg mtdblock3 timer video3
log mtdblock4 tty watchdog
mem mtdblock5 tty0 zero
mmcblk0 mtdblock6 tty1
两者的差别就是设备rtc0.
3.2 问题分析
从上述信息可知,rtc创建有问题,在rtc-ds3232.c 的ds3232_probe函数中添加调试信息,发现ds3232_probe函数根本没有被调用,这说明在上层rtc没有匹配驱动,那重点关注设备驱动static struct i2c_driver ds3232_driver 中的name 和id_table,
static const struct i2c_device_id ds3232_id[] = {
{ "ds3232", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ds3232_id);
static struct i2c_driver ds3232_driver = {
.driver = {
.name = "rtc-ds3232",
.owner = THIS_MODULE,
},
.probe = ds3232_probe,
.remove = __devexit_p(ds3232_remove),
.id_table = ds3232_id,
};
如上述代码,其中.name = "rtc-ds3232",和在板级配置中时一致的,但是.id_table = ds3232_id的名称为ds3232,这样device和driver 匹配时肯定不能成功。先修改ds3232为rtc-ds3232