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驱动模型结构如下图:
图3-1 RTC驱动模型
2. I2C驱动模型
对于采用I2C总线的RTC芯片,它的驱动不仅仅需要RTC的驱动,还需要I2C驱动的支持。对于Linux下,自身的I2C驱动已经比较完善,只要添加RTC设备支持即可。
四、修改内核配置
1. 增加I2C字符设备的支持
位置 DeviceDriver--> Character devices--> Ralink RT2880 I2C Support,将其选择为模块,如图4-1所示。
图4-1 Ralink对 I2C字符设备的支持
2. I2C设备的配置
(1)配置I2C
DeviceDriver--> I2C support,配置为图4-2所示
图4-2 I2C支持配置
(2)配置I2C的总线协议
对于SMBUS-specificprotocols 中,需要设置一下I2C Algorithms,选择协议“I2C bit-banging”,否则,即使rtc驱动正确,也不能使用。
位置:Device Driver -->I2C support --> SMBus-specific protocols --> I2C Algorithms
配置为如图4-3所示。
图4-3 I2C Algorithms配置
(3)增加硬件I2C 总线支持
Device Driver --> I2C support -->I2C Hardware Bus support
选择增加Ralink 的I2C总线控制器,如图4-4所示。
图4-4 硬件I2C总线支持
3. RTC配置
(1)开启RTC
Device Driver --> Real Time Clock
选择RTC,如图4-5所示
图 4-5 开启RTC配置
(2)RTC配置
Device Driver --> Real Time Clock
在图4-5中,再选择RTC的配置,如图4-6配置。
图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 $*.o obj-y := reset.o init.o irq.o \ memory.o printf.o cmdline.o setup.o time.o ifeq ($(CONFIG_MIPS_MT_SMP),y) obj-y += malta-amon.o endif obj-$(CONFIG_KERNEL_NVRAM) += nvram.o obj-$(CONFIG_PCI) += pci.o obj-$(CONFIG_DWC_OTG) += lm.o obj-$(CONFIG_RALINK_TIMER_WDG) += ralink_wdt.o obj-$(CONFIG_RALINK_TIMER_DFS) += rt_timer.o obj-$(CONFIG_RT_DMA) += dev-dma.o obj-$(CONFIG_MTK_MTD_NAND) += dev-nand.o ifeq ($(CONFIG_RALINK_MT7621),y) obj-$(CONFIG_MTD_ANY_RALINK) += dev-nand.o endif #obj-$(CONFIG_I2C_RALINK) += dev-i2c.o # source code obj-$(CONFIG_I2C_RALINK) += dev-i2c.o # add by sky.houfei 2015-10-27 obj-$(CONFIG_RALINK_RT3883) += ehci_ohci.o udc.o obj-$(CONFIG_RALINK_RT3352) += ehci_ohci.o udc.o obj-$(CONFIG_RALINK_RT5350) += ehci_ohci.o udc.o obj-$(CONFIG_RALINK_RT6855) += ehci_ohci.o udc.o obj-$(CONFIG_RALINK_MT7620) += ehci_ohci.o udc.o obj-$(CONFIG_RALINK_MT7628) += ehci_ohci.o udc.o ifeq ($(CONFIG_CONFIG_SHRINK),y) EXTRA_CFLAGS += -DCONFIG_SHRINK #-DHT_DEBUG #-DHASH_STAT_DBG obj-y += hash_utils.o #list_utils.o endif
(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-19 return 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 0x01 struct 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 10 static 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.o PWD=$(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) modules clean: make ARCH=mips CROSS_COMPILE="/opt/buildroot-gcc463/usr/bin"/mipsel-linux- -C $(KDIR) M=$(PWD) clean rm -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芯片通信。