ds3231 linux驱动移植

一、需求分析:    
二、驱动移植    
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
 

你可能感兴趣的:(Linux,驱动)