背景
产品客户需要时间能够设置到2038以后,所以需要去解决这个问题,通过查阅资料可知,linux内核在5.6的版本就已经修复了2038的问题,但是目前产品使用的是3.10的版本,所以这个问题仍然存在,但是未能找到针对3.10版本的补丁,自己去修改的话,因为修改时间相关的比较多,没有太大的把握。
针对上面的问题,和根据产品情况,有下面两个方案的可行性比较高:
- 直接操作rtc时间,摒弃linux系统本身的接口去获取时间,就不受linux系统本身时间存储位数的限制了
- 通过网络同步时间
本文章讲述的是方式一。
实现原理
修改rtc驱动源码接口,直接读取和设置rtc的时间,这边脱离了linux内核的限制
代码实现
关键修改,现在使用的rtc芯片是rv-8263-c7:
static int rtc_drv_open(struct inode *inode, struct file *file)
{
// printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
return 0;
}
static ssize_t rtc_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
// printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
// int val;
// copy_from_user(&val, buf, count); // copy_to_user();
// printk("val = %d\n",val);
// if(val == 1)
// {
// for(int i = 0;i<6;i++)
// midea_code[i] = 0xff;
// }
int time[7];
copy_from_user(time, buf, sizeof(time));
int tm_sec,tm_min,tm_hour,tm_mday,tm_wday,tm_mon,tm_year;
tm_sec = time[0];
tm_min = time[1];
tm_hour = time[2];
tm_mday = time[3];
tm_wday = time[4];
tm_mon = time[5];
// tm_year = time[6];
tm_year = time[6]-1900;
// printk("time->tm_year=%d time->tm_mon=%d time->tm_wday=%d time->tm_mday=%d \
// time->tm_hour=%d time->tm_min=%d time->tm_sec=%d\n",tm_year,tm_mon,\
// tm_wday,tm_mday,tm_hour,tm_min,tm_sec);
u8 regs[7];
int ret;
u8 buf1[1];
/*置1*/
ret = pcf85063_i2c_read_regs(rv8263_client, PCF85063_REG_CTRL1,buf1, 1);
if (ret < 0) {
dev_err(&rv8263_client->dev, "can't read PCF85063_REG_CTRL1 reg\n");
return ret;
}
buf1[0] |= (1<<5);
ret = pcf85063_i2c_write_regs(rv8263_client, PCF85063_REG_CTRL1, buf1, 1);
if (ret < 0) {
dev_err(&rv8263_client->dev, "can't set PCF85063_REG_CTRL1 reg\n");
return ret;
}
/* hours, minutes and seconds */
regs[0] = bin2bcd(tm_sec) & 0x7F; /* clear OS flag */
regs[1] = bin2bcd(tm_min);
regs[2] = bin2bcd(tm_hour);
/* Day of month, 1 - 31 */
regs[3] = bin2bcd(tm_mday);
/* Day, 0 - 6 */
regs[4] = tm_wday & 0x07;
/* month, 1 - 12 */
regs[5] = bin2bcd(tm_mon + 1);
/* year and century */
regs[6] = bin2bcd(tm_year - 100);
ret = pcf85063_i2c_write_regs(rv8263_client, PCF85063_REG_SC, regs,
PCF85063_WATCH_SECTION_LEN);
if (ret < 0)
return ret;
/*置0*/
ret = pcf85063_i2c_read_regs(rv8263_client, PCF85063_REG_CTRL1,buf1, 1);
if (ret < 0) {
dev_err(&rv8263_client->dev, "can't read PCF85063_REG_CTRL1 reg\n");
return ret;
}
buf1[0] &= (~(1<<5));
ret = pcf85063_i2c_write_regs(rv8263_client, PCF85063_REG_CTRL1, buf1, 1);
if (ret < 0) {
dev_err(&rv8263_client->dev, "can't set PCF85063_REG_CTRL1 reg\n");
return ret;
}
return 0;
}
static ssize_t rtc_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
// printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
int tm_sec,tm_min,tm_hour,tm_mday,tm_wday,tm_mon,tm_year;
int time[7];
int ret;
u8 regs[PCF85063_WATCH_SECTION_LEN] = { 0, };
ret = pcf85063_i2c_read_regs(rv8263_client, PCF85063_REG_SC , regs,
PCF85063_WATCH_SECTION_LEN);
if (ret < 0) {
dev_err(&rv8263_client->dev, "%s: reading RTC section failed\n",
__func__);
return ret;
}
tm_sec = bcd2bin(regs[0] & 0x7F);
tm_min = bcd2bin(regs[1] & 0x7F);
tm_hour = bcd2bin(regs[2] & 0x3F);/* rtc hr 0-23 */
tm_mday =bcd2bin(regs[3] & 0x3F);
tm_wday = regs[4] & 0x07;
tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
tm_year = bcd2bin(regs[6]);
tm_year += 100;
time[0] = tm_sec;
time[1] = tm_min;
time[2] = tm_hour;
time[3] = tm_mday;
time[4] = tm_wday;
time[5] = tm_mon;
time[6] = tm_year+1900;
// printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
// printk("time->tm_year=%d time->tm_mon=%d time->tm_wday=%d time->tm_mday=%d \
// time->tm_hour=%d time->tm_min=%d time->tm_sec=%d\n",tm_year,tm_mon,\
// tm_wday,tm_mday,tm_hour,tm_min,tm_sec);
ret = copy_to_user(buf, time, sizeof(time));
// printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
return 0;
}
static struct file_operations rtc_drv_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = rtc_drv_open,
.write = rtc_drv_write,
.read = rtc_drv_read,
};
int major;
static int pcf85063_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rtc_device *rtc;
int rc = 0;
u8 buf[1];
rv8263_client = client;
// printk("%s %d %s\n",__FILE__,__LINE__,__FUNCTION__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))
return -ENODEV;
rtc = devm_rtc_device_register(&client->dev, client->name,
&pcf85063_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
i2c_set_clientdata(client, rtc);
/*修改之处*/
rc = pcf85063_i2c_get_sr(client, buf);
if (rc < 0) {
dev_err(&client->dev, "RTC chip is not present\n");
return rc;
}
rc = pcf85063_i2c_read_regs(client, PCF85063_REG_CTRL1,buf, 1);
if (rc < 0) {
dev_err(&client->dev, "can't read PCF85063_REG_CTRL1 reg\n");
return rc;
}
buf[0] &= 0;
rc = pcf85063_i2c_write_regs(client, PCF85063_REG_CTRL1, buf, 1);
if (rc < 0) {
dev_err(&client->dev, "can't set PCF85063_REG_CTRL1 reg\n");
return rc;
}
rc = device_create_file(&client->dev, &dev_attr_reg_value);
major = register_chrdev(0, "rtc_drv", &rtc_drv_fops); // 注册, 告诉内核
rtc_cls = class_create(THIS_MODULE, "rtc_drv");
rtc_device = device_create(rtc_cls, NULL, MKDEV(major, 0), NULL, "rtc1"); /* /dev/gpio_midea */
return 0;
}
主要修改是增加了read/write接口直接对rtc寄存器进行操作。也附上完整代码