Linux 关于MCP7940 RTC驱动(MT7620芯片)

来源:互联网 发布:steinberg软件 编辑:程序博客网 时间:2024/06/15 08:38

http://www.itdadao.com/articles/c15a194465p0.html


一、硬件平台

        1、  控制器:MT7620(A9内核)

        2、  RTC芯片:MCP7940

二、软件平台

       1、开发环境:Ubuntu12.04 

       2、SDK内核包:MT7620 SDK软件开发包(MediaTek_ApSoC_SDK_4320_20150414.tar.bz2)

       3、内核版本:linux-2.6.36.x

三、功能简介

        RTC(real time clock)实时时钟,主要作用是给Linux系统提供时间。本文中的RTC为单独的RTC芯片MCP7940,与CPU采用I2C总线连接。

    1.      RTC驱动模式

         与RTC核心有关的文件有:
        /drivers/rtc/class.c         这个文件向linux设备模型核心注册了一个类RTC,然后向驱动程序提供了注册/注销接口
        /drivers/rtc/rtc-dev.c       这个文件定义了基本的设备文件操作函数,如:open,read等
        /drivers/rtc/interface.c     顾名思义,这个文件主要提供了用户程序与RTC驱动的接口函数,用户程序一般通过ioctl与RTC驱动交互,这里定义了每个ioctl命令需要调用的函数
        /drivers/rtc/rtc-sysfs.c     与sysfs有关
        /drivers/rtc/rtc-proc.c      与proc文件系统有关
        /include/linux/rtc.h         定义了与RTC有关的数据结构

        RTC驱动模型结构如下图:

itdadao-Linux 关于MCP7940 RTC驱动(MT7620芯片)

图3-1 RTC驱动模型

    2. I2C驱动模型

        对于采用I2C总线的RTC芯片,它的驱动不仅仅需要RTC的驱动,还需要I2C驱动的支持。对于Linux下,自身的I2C驱动已经比较完善,只要添加RTC设备支持即可。

 

四、修改内核配置

     1. 增加I2C字符设备的支持

        位置 DeviceDriver--> Character devices--> Ralink RT2880 I2C Support,将其选择为模块,如图4-1所示。

itdadao-Linux 关于MCP7940 RTC驱动(MT7620芯片)

                      图4-1  Ralink对 I2C字符设备的支持

 

     2. I2C设备的配置

      (1)配置I2C

          DeviceDriver--> I2C support,配置为图4-2所示

itdadao-Linux 关于MCP7940 RTC驱动(MT7620芯片)

  图4-2  I2C支持配置

 

     (2)配置I2C的总线协议

        对于SMBUS-specificprotocols 中,需要设置一下I2C Algorithms,选择协议“I2C bit-banging”,否则,即使rtc驱动正确,也不能使用。

        位置:Device Driver -->I2C support --> SMBus-specific protocols --> I2C Algorithms

        配置为如图4-3所示。

itdadao-Linux 关于MCP7940 RTC驱动(MT7620芯片)

图4-3  I2C Algorithms配置

 

     (3)增加硬件I2C 总线支持

        Device Driver --> I2C support -->I2C Hardware Bus support

        选择增加Ralink 的I2C总线控制器,如图4-4所示。

itdadao-Linux 关于MCP7940 RTC驱动(MT7620芯片)

        图4-4 硬件I2C总线支持

 

    3. RTC配置

    (1)开启RTC

        Device Driver --> Real Time Clock

        选择RTC,如图4-5所示

itdadao-Linux 关于MCP7940 RTC驱动(MT7620芯片)

图 4-5  开启RTC配置

 

     (2)RTC配置

        Device Driver --> Real Time Clock

        在图4-5中,再选择RTC的配置,如图4-6配置。

itdadao-Linux 关于MCP7940 RTC驱动(MT7620芯片)

图4-6 RTC配置

        注意,图4-6中的 “RTC debug support”建议开启,可以查看RTC的调试信息,例如RTC 驱动成功的话,系统会打印如下信息:

        “rtc-mcp7940 0-006f: rtc core: registered mcp7940 as rtc0”

 

五、RTC驱动代码

      1. MT7620的内核代码

     (1)修改SDK开发包的makefile。

           因为默认的makefile,把I2C的编译部分给屏蔽了,所以需要手动修改:linux-2.6.36.x/arch/mips/ralink/MAKEFIL。

          原始代码:

#obj-$(CONFIG_I2C_RALINK) +=  dev-i2c.o
         修改之后:
obj-$(CONFIG_I2C_RALINK) +=  dev-i2c.o
        修改之后的makefile如下:

################################################################################  Jan 2007 Bruce Chang##  Initial Release##################################################################################.S.s:$(CPP) $(CFLAGS) $< -o $*.s.S.o:$(CC) $(CFLAGS) -c $< -o $*.oobj-y    := reset.o init.o irq.o \            memory.o printf.o cmdline.o setup.o time.oifeq ($(CONFIG_MIPS_MT_SMP),y)obj-y += malta-amon.oendifobj-$(CONFIG_KERNEL_NVRAM) += nvram.oobj-$(CONFIG_PCI) += pci.oobj-$(CONFIG_DWC_OTG) += lm.oobj-$(CONFIG_RALINK_TIMER_WDG) +=  ralink_wdt.oobj-$(CONFIG_RALINK_TIMER_DFS) +=  rt_timer.oobj-$(CONFIG_RT_DMA) +=  dev-dma.oobj-$(CONFIG_MTK_MTD_NAND) +=  dev-nand.oifeq ($(CONFIG_RALINK_MT7621),y)obj-$(CONFIG_MTD_ANY_RALINK) +=  dev-nand.oendif#obj-$(CONFIG_I2C_RALINK) +=  dev-i2c.o   # source codeobj-$(CONFIG_I2C_RALINK) +=  dev-i2c.o    # add by sky.houfei 2015-10-27obj-$(CONFIG_RALINK_RT3883) +=  ehci_ohci.o udc.oobj-$(CONFIG_RALINK_RT3352) +=  ehci_ohci.o udc.oobj-$(CONFIG_RALINK_RT5350) +=  ehci_ohci.o udc.oobj-$(CONFIG_RALINK_RT6855) +=  ehci_ohci.o udc.oobj-$(CONFIG_RALINK_MT7620) +=  ehci_ohci.o udc.oobj-$(CONFIG_RALINK_MT7628) +=  ehci_ohci.o udc.oifeq ($(CONFIG_CONFIG_SHRINK),y)EXTRA_CFLAGS += -DCONFIG_SHRINK #-DHT_DEBUG #-DHASH_STAT_DBGobj-y += hash_utils.o #list_utils.oendif

    (2)修改I2C代码

        修改I2C对设备的支持,增加MCP7940设备的支持。修改文件为:linux-2.6.36.x/arch/mips/ralink/dev_i2c.c

        对于MCP7940,其i2c设备结构如下

static struct i2c_board_info __initdata mcp7940_i2c_devices[] = {{ I2C_BOARD_INFO("rtc-mcp7940", 0x6f),  .type = "mcp7940",  /* REVISIT .irq = IRQ4 ... this RTC has an alarm */},};
      其中,查看MCP7940芯片手册,可以得知设备的I2C总线通信地址为 1101 111x

      最后一位为读写位。对于Linux I2C而言,所有的I2C设备的地址,都为芯片手册中的地址右移一位的数值,所以MCP7940在I2C设备结构中的地址为 1101 111x >> 1,结果为 0110 1111,即为 0x6f

       修改之后的dev_i2c.c代码如下所示:

#include <linux/init.h>#include <linux/kernel.h>#include <linux/platform_device.h>#include <linux/i2c/at24.h>#include <linux/i2c.h>#include <asm/mach-ralink/rt_mmap.h>static struct at24_platform_data at24_config = {.byte_len= 0x400 / 8,.page_size= 8,};static struct i2c_board_info i2c_info[] __initconst =  {{I2C_BOARD_INFO("24c01", 0x50),.platform_data= http://blog.csdn.net/xhoufei2010/article/details/&at24_config,},};// ========= sourc code start ============//#if 0   //static struct i2c_board_info __initdata mpc8313_i2c_devices[] = {//{ I2C_BOARD_INFO("rtc-ds1307", 0x68),//  .type = "ds1339",//  /* REVISIT .irq = IRQ4 ... this RTC has an alarm *///},//};//#endif// ========= sourc code end ============// ======= add by sky.houfei =============static struct i2c_board_info __initdata mcp7940_i2c_devices[] = {{ I2C_BOARD_INFO("rtc-mcp7940", 0x6f),  .type = "mcp7940",  /* REVISIT .irq = IRQ4 ... this RTC has an alarm */},};// ============ add end ============static struct resource i2c_resources[] = {{.start= -1, /* filled at runtime */.end= -1, /* filled at runtime */.flags= IORESOURCE_MEM,},};static struct platform_device ralink_i2c_device = {.name= "Ralink-I2C",.id= 0,.num_resources= ARRAY_SIZE(i2c_resources),.resource= i2c_resources,};int __init ralink_i2c_register(void){i2c_resources[0].start = RALINK_I2C_BASE;i2c_resources[0].end += RALINK_I2C_BASE + 256 - 1;platform_device_register(&ralink_i2c_device);i2c_register_board_info(0, i2c_info, ARRAY_SIZE(i2c_info));// ======== sourc code start========//#if 0   //    i2c_register_board_info(0, mpc8313_i2c_devices, ARRAY_SIZE(mpc8313_i2c_devices));//#endif   // ======== sourc code end========i2c_register_board_info(0, mcp7940_i2c_devices, ARRAY_SIZE(mcp7940_i2c_devices)); //add by sky.houfei 2015-10-19return 0;}arch_initcall(ralink_i2c_register);

2. MCP7940驱动

        驱动对应的文件名为:rtc_mcp7940.c

/* * rtc-mcp7940.c - RTC driver for some mostly-compatible I2C chips. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/string.h>#include <linux/rtc.h>#include <linux/bcd.h>#include <asm/mach-ralink/rt_mmap.h>#define RALINK_SYSCTL_ADDR       RALINK_SYSCTL_BASE    // system control #define RALINK_REG_GPIOMODE      (RALINK_SYSCTL_ADDR + 0x60) // GPIO MODE/* We can't determine type by probing, but if we expect pre-Linux code * to have set the chip up as a clock (turning on the oscillator and * setting the date and time), Linux can ignore the non-clock features. * That's a natural job for a factory or repair bench. */enum ds_type {mcp7940,};/* RTC registers don't differ much, except for the century flag */#define MCP7940_REG_SECS         0x00    /* 00-59 */#define MCP7940_BIT_CH           0x80#define MCP7940_BIT_ST           0x80#define MCP7940_REG_MIN          0x01    /* 00-59 */#define MCP7940_REG_HOUR         0x02    /* 00-23, or 1-12{am,pm} */#define MCP7940_BIT_12HR         0x40    /* in REG_HOUR */#define MCP7940_BIT_PM           0x20    /* in REG_HOUR */#define MCP7940_REG_WDAY         0x03    /* 01-07 */#define MCP7940_REG_MDAY         0x04    /* 01-31 */#define MCP7940_REG_MONTH        0x05    /* 01-12 */#define MCP7940_REG_YEAR         0x06    /* 00-99 */#define MCP7940_BIT_VBATEN       0x08/* Other registers (control, status, alarms, trickle charge, NVRAM, etc) * start at 7, and they differ a LOT. Only control and status matter for * basic RTC date and time functionality; be careful using them. */#define MCP7940_REG_CONTROL      0x07#define MCP7940_BIT_OUT          0x80#define MCP7940_BIT_SQWE         0x10#define MCP7940_BIT_RS1          0x02#define MCP7940_BIT_RS0          0x01struct mcp7940 {        u8                      offset; /* register's offset */        u8                      regs[11];        enum ds_type            type;        unsigned long           flags;#define HAS_NVRAM       0               /* bit 0 == sysfs file active */#define HAS_ALARM       1               /* bit 1 == irq claimed */        struct i2c_client       *client;        struct rtc_device       *rtc;        struct work_struct      work;        s32 (*read_block_data)(struct i2c_client *client, u8 command,                               u8 length, u8 *values);        s32 (*write_block_data)(struct i2c_client *client, u8 command,                                u8 length, const u8 *values);};struct chip_desc {        unsigned                nvram56:1;        unsigned                alarm:1;};static const struct i2c_device_id mcp7940_id[] = {        { "mcp7940", mcp7940 },        { }};MODULE_DEVICE_TABLE(i2c, mcp7940_id);/*----------------------------------------------------------------------*/#define BLOCK_DATA_MAX_TRIES 10static s32 mcp7940_read_block_data_once(struct i2c_client *client, u8 command,                                  u8 length, u8 *values){        s32 i, data;        for (i = 0; i < length; i++) {                data = http://blog.csdn.net/xhoufei2010/article/details/i2c_smbus_read_byte_data(client, command + i);                if (data < 0)                        return data;                values[i] = data;        }        return i;}static s32 mcp7940_read_block_data(struct i2c_client *client, u8 command,                                  u8 length, u8 *values){        u8 oldvalues[I2C_SMBUS_BLOCK_MAX];        s32 ret;        int tries = 0;        dev_dbg(&client->dev,"mcp7940_read_block_data (length=%d)\n", length);        ret = mcp7940_read_block_data_once(client, command, length, values);        if (ret < 0)                return ret;        do {                if (++tries > BLOCK_DATA_MAX_TRIES) {                        dev_err(&client->dev,                                "mcp7940_read_block_data failed\n");                        return -EIO;                }                memcpy(oldvalues, values, length);                ret = mcp7940_read_block_data_once(client, command, length,                                                  values);                if (ret < 0)                        return ret;        } while (memcmp(oldvalues, values, length));        return length;}static s32 mcp7940_write_block_data(struct i2c_client *client, u8 command,                                   u8 length, const u8 *values){    u8 currvalues[I2C_SMBUS_BLOCK_MAX];    int tries = 0;    dev_dbg(&client->dev, "mcp7940_write_block_data (length=%d)\n", length);    do {            s32 i, ret;            if (++tries > BLOCK_DATA_MAX_TRIES) {                    dev_err(&client->dev,                            "mcp7940_write_block_data failed\n");                    return -EIO;            }            for (i = 0; i < length; i++) {                    ret = i2c_smbus_write_byte_data(client, command + i,                                                    values[i]);                    if (ret < 0)                            return ret;            }            ret = mcp7940_read_block_data_once(client, command, length,                                              currvalues);            if (ret < 0)                    return ret;    } while (memcmp(currvalues, values, length));    return length;}static int mcp7940_get_time(struct device *dev, struct rtc_time *t){        struct mcp7940  *mcp7940 = dev_get_drvdata(dev);        int             tmp;        /* read the RTC date and time registers all at once */        tmp = mcp7940->read_block_data(mcp7940->client,                mcp7940->offset, 7, mcp7940->regs);        if (tmp != 7) {                dev_err(dev, "%s error %d\n", "read", tmp);                return -EIO;        }        dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",                        "read",                        mcp7940->regs[0], mcp7940->regs[1],                        mcp7940->regs[2], mcp7940->regs[3],                        mcp7940->regs[4], mcp7940->regs[5],                        mcp7940->regs[6]);        t->tm_sec = bcd2bin(mcp7940->regs[MCP7940_REG_SECS] & 0x7f);        t->tm_min = bcd2bin(mcp7940->regs[MCP7940_REG_MIN] & 0x7f);        tmp = mcp7940->regs[MCP7940_REG_HOUR] & 0x3f;        t->tm_hour = bcd2bin(tmp);        t->tm_wday = bcd2bin(mcp7940->regs[MCP7940_REG_WDAY] & 0x07) - 1;        t->tm_mday = bcd2bin(mcp7940->regs[MCP7940_REG_MDAY] & 0x3f);        tmp = mcp7940->regs[MCP7940_REG_MONTH] & 0x1f;        t->tm_mon = bcd2bin(tmp) - 1;        /* assume 20YY not 19YY, and ignore DS1337_BIT_CENTURY */        t->tm_year = bcd2bin(mcp7940->regs[MCP7940_REG_YEAR]) + 100;        dev_dbg(dev, "%s secs=%d, mins=%d, "                "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",                "read", t->tm_sec, t->tm_min,                t->tm_hour, t->tm_mday,                t->tm_mon, t->tm_year, t->tm_wday);        /* initial clock setting can be undefined */        return rtc_valid_tm(t);}static int mcp7940_set_time(struct device *dev, struct rtc_time *t){        struct mcp7940  *mcp7940 = dev_get_drvdata(dev);        int             result;        int             tmp;        u8              *buf = mcp7940->regs;        dev_dbg(dev, "%s secs=%d, mins=%d, "                "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",                "write", t->tm_sec, t->tm_min,                t->tm_hour, t->tm_mday,                t->tm_mon, t->tm_year, t->tm_wday);        buf[MCP7940_REG_SECS] = bin2bcd(t->tm_sec);        buf[MCP7940_REG_MIN] = bin2bcd(t->tm_min);        buf[MCP7940_REG_HOUR] = bin2bcd(t->tm_hour);        buf[MCP7940_REG_WDAY] = bin2bcd(t->tm_wday + 1);        buf[MCP7940_REG_MDAY] = bin2bcd(t->tm_mday);        buf[MCP7940_REG_MONTH] = bin2bcd(t->tm_mon + 1);        /* assume 20YY not 19YY */        tmp = t->tm_year - 100;        buf[MCP7940_REG_YEAR] = bin2bcd(tmp);                buf[MCP7940_REG_SECS] |= MCP7940_BIT_ST;                buf[MCP7940_REG_WDAY] |= MCP7940_BIT_VBATEN;        dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",                "write", buf[0], buf[1], buf[2], buf[3],                buf[4], buf[5], buf[6]);        result = mcp7940->write_block_data(mcp7940->client,                mcp7940->offset, 7, buf);        if (result < 0) {                dev_err(dev, "%s error %d\n", "write", result);                return result;        }        return 0;}static int mcp7940_ioctl(struct device *dev, unsigned int cmd, unsigned long arg){struct rtc_time time;void __user *uarg = (void __user *) arg;    switch (cmd) {case RTC_RD_TIME:mcp7940_get_time(dev, &time);if (copy_to_user(uarg, &time, sizeof(time))){printk("RTC_RD_TIME error, can not copy to user\n");return -EFAULT;}break;case RTC_SET_TIME:if (copy_from_user(&time, uarg, sizeof(time))){printk("RTC_SET_TIME error, can not copy from user\n");return -EFAULT;}mcp7940_set_time(dev, &time);break;    default:        return -ENOIOCTLCMD;    }    return 0;}static const struct rtc_class_ops mcp7940_rtc_ops = {.read_time = mcp7940_get_time,.set_time  = mcp7940_set_time,.ioctl     = mcp7940_ioctl,};/*----------------------------------------------------------------------*/static struct i2c_driver mcp7940_driver;static int __devinit mcp7940_probe(struct i2c_client *client,                                  const struct i2c_device_id *id){    struct mcp7940          *mcp7940;    int                     err = -ENODEV;    int                     tmp;    struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);    unsigned char           *buf;    if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)        && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))            return -EIO;    if (!(mcp7940 = kzalloc(sizeof(struct mcp7940), GFP_KERNEL)))            return -ENOMEM;    i2c_set_clientdata(client, mcp7940);    mcp7940->client = client;    mcp7940->type   = id->driver_data;    mcp7940->offset = 0;    buf = mcp7940->regs;    if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {            mcp7940->read_block_data = http://blog.csdn.net/xhoufei2010/article/details/i2c_smbus_read_i2c_block_data;            mcp7940->write_block_data = i2c_smbus_write_i2c_block_data;    } else {            mcp7940->read_block_data = mcp7940_read_block_data;            mcp7940->write_block_data = mcp7940_write_block_data;    }read_rtc:        /* read RTC registers */        tmp = mcp7940->read_block_data(mcp7940->client, 0, 8, buf);        if (tmp != 8) {                pr_debug("read error %d\n", tmp);                err = -EIO;                goto exit_free;        }        /* minimal sanity checking; some chips (like DS1340) don't         * specify the extra bits as must-be-zero, but there are         * still a few values that are clearly out-of-range.         */        tmp = mcp7940->regs[MCP7940_REG_SECS];                /* make sure that the backup battery is enabled */                if (!(mcp7940->regs[MCP7940_REG_WDAY] & MCP7940_BIT_VBATEN)) {                        i2c_smbus_write_byte_data(client, MCP7940_REG_WDAY,                                mcp7940->regs[MCP7940_REG_WDAY]                                | MCP7940_BIT_VBATEN);                }                /* clock halted?  turn it on, so clock can tick. */                if (!(tmp & MCP7940_BIT_ST)) {                        i2c_smbus_write_byte_data(client, MCP7940_REG_SECS,                                MCP7940_BIT_ST);                        dev_warn(&client->dev, "SET TIME!\n");                        goto read_rtc;                }        tmp = mcp7940->regs[MCP7940_REG_HOUR];        switch (mcp7940->type) {        default:                if (!(tmp & MCP7940_BIT_12HR))                        break;                /* Be sure we're in 24 hour mode.  Multi-master systems                 * take note...                 */                tmp = bcd2bin(tmp & 0x1f);                if (tmp == 12)                        tmp = 0;                if (mcp7940->regs[MCP7940_REG_HOUR] & MCP7940_BIT_PM)                        tmp += 12;                i2c_smbus_write_byte_data(client,                                MCP7940_REG_HOUR,                                bin2bcd(tmp));        }        mcp7940->rtc = rtc_device_register(client->name, &client->dev,                                &mcp7940_rtc_ops, THIS_MODULE);        if (IS_ERR(mcp7940->rtc)) {                err = PTR_ERR(mcp7940->rtc);                dev_err(&client->dev,                        "unable to register the class device\n");                goto exit_free;        }    return 0;exit_free:        kfree(mcp7940);        return err;}static int __devexit mcp7940_remove(struct i2c_client *client){struct mcp7940          *mcp7940 = i2c_get_clientdata(client);    rtc_device_unregister(mcp7940->rtc);    kfree(mcp7940);    return 0;}static struct i2c_driver mcp7940_driver = {    .driver = {        .name   = "rtc-mcp7940",        .owner  = THIS_MODULE,    },    .probe          = mcp7940_probe,    .remove         = __devexit_p(mcp7940_remove),    .id_table       = mcp7940_id,};static void rtc_pin_mux_init(void){u32 mode = 0;mode = le32_to_cpu(*(volatile u32 *)(RALINK_REG_GPIOMODE));     mode &= ~(0x1 << 0); // I2C_GPIO_MODE引脚,设置为I2C模式,即I2C_SD(GPIO#1)I2C_SCLK(GPIO#2)都设置为I2C模式    *(volatile u32 *)(RALINK_REG_GPIOMODE) = cpu_to_le32(mode); }static int __init mcp7940_init(void){rtc_pin_mux_init();    return i2c_add_driver(&mcp7940_driver);}module_init(mcp7940_init);static void __exit mcp7940_exit(void){        i2c_del_driver(&mcp7940_driver);}module_exit(mcp7940_exit);MODULE_AUTHOR("sky.houfei");MODULE_DESCRIPTION("RTC driver for MCP7940");MODULE_LICENSE("GPL");


3.mc7940驱动对应的Makefile

obj-m = rtc_mcp7940.oPWD=$(shell pwd)KDIR = /home/sky/develop/kernel/sau2ag1/source/linux-2.6.36.x/all:make  ARCH=mips CROSS_COMPILE="/opt/buildroot-gcc463/usr/bin"/mipsel-linux-  -C $(KDIR)  M=$(PWD) modulesclean:make  ARCH=mips CROSS_COMPILE="/opt/buildroot-gcc463/usr/bin"/mipsel-linux-  -C $(KDIR)  M=$(PWD) cleanrm -f rtc_mcp7940.ko  #make command:#make  #make clean

4. mcp7940应用程序

        mcp7940应用程序为 rtc_app.c,应用中,存储的时间为UTC格式时间,对于UTC时间,year = year -1900, month = month -1,应用程序如下。

/* *      Real Time Clock Driver Test/Example Program * *      Compile with: *     mipsel-linux-gcc rtc_app.c -o rtc_app *      Released under the GNU General Public License, version 2, *      included herein by reference. * */ #include <stdio.h> #include <linux/rtc.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <errno.h>/* * This expects the new RTC class driver framework, working with * clocks that will often not be clones of what the PC-AT had. * Use the command line to specify another RTC if you need one. */ static const char default_rtc[] = "/dev/rtc0";int main(int argc, char **argv) { int i, fd, retval, irqcount = 0;unsigned int cmd = 0;unsigned long tmp, data;struct rtc_time rtc_tm;const char *rtc = default_rtc;fd = open(default_rtc, O_RDONLY);if (fd == -1){printf("Can not open %s, exit the app\n", default_rtc);}rtc_tm.tm_year = 2016 - 1900;rtc_tm.tm_mon = 1 - 1;rtc_tm.tm_mday = 4;rtc_tm.tm_wday = 1;rtc_tm.tm_hour = 10;rtc_tm.tm_min = 23;rtc_tm.tm_sec = 53;i = atoi(argv[1]);switch(i){case 1:cmd = RTC_RD_TIME;break;case 2:cmd = RTC_SET_TIME;printf("app set time %d-%d-%d week%d, %02d:%02d:%02d.\n", rtc_tm.tm_year + 1900, rtc_tm.tm_mon, rtc_tm.tm_mday, rtc_tm.tm_wday,rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);break;default:cmd = RTC_RD_TIME;break;}retval = ioctl(fd, cmd, &rtc_tm);if (retval == -1) { printf("ioctl cmd = %d, error, exit the rtc app\n");exit(errno); }printf("rtc app date/time is %d-%d-%d week%d, %02d:%02d:%02d.\n", rtc_tm.tm_year + 1900, rtc_tm.tm_mon + 1, rtc_tm.tm_mday, rtc_tm.tm_wday,rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);close(fd);printf("rtc test end\n");return 0; } 


六、常见问题分析

        1. 如果查看设备的文件:

          /dev/i2c-0 提示ic2初始化正确。

         /sys/bus/i2c/drivers/rtc-mcp7940   提示I2C总线挂载了一个名叫rtc-mcp7940 的设备,但是并不意味着总线已经可以和该设备通信,驱动的probe函数有可能都没有执行。

        /dev/rtc0 说明设备已经加载成功,I2C总线成功的和RTC芯片通信。



0 0
原创粉丝点击