软件开发平台:android P 源码。
硬件开发平台:nxp imx8m mini开发板,RTC 型号8025T。

本文记录在nxp 8m mini 硬件平台, android P 源码的软件平台上调试RTC8025T驱动,RTC的framework 层android 已经写好了即 AlarmManagerService , APP 应用层通过((AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE)) 提供的接口来读取和设置 RTC 。

一.RTC相关驱动调试
先来了解下 RTC 8025T 操作模式:
操作模式 :
1 ) 实时时钟模式
实时时 钟模式
该功能被用来设定和读取年,月,日,星期,时,分,秒 时间信息。年份为后两位数字表示,
任何可以被 4 整除的年份被当成闰年处理。(2000 年到 2099 年)
2 ) 固定周期的中断发生功能:
固定周期的中断发生功能
固定周期定时中断发生功能可以产生一个固定周期的中断事件,固定周期可在 244.14uS 到
4095 分钟之间的 任意时间设定。
3)定时更新中断功能:
该功能可以根据内部时钟的定时设定,每秒或每分钟产生一个中断事件。
当中断事件产生,UF 标志位的值变成 1 同时/INT 引脚变成低电平表示一个中断事件的产生。
4 ) 闹钟中断功能
闹钟 中断功能:
中断功能
该功能可以根据报警设定来产生一个中断。
硬件电路设计如下:

Nxp 平台有有完整的RTC驱动框架,所以只需要完善8025T相关的读写功能就可以了。

初始化8025T

static int rx8025_probe(struct i2c_client *client,         const struct i2c_device_id *id){   struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);   struct rx8025_data *rx8025;   int err = 0;   //可以看到RTC 驱动初始化的上下文    dump_stack();   rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);      rx8025->client = client;   i2c_set_clientdata(client, rx8025);   err = rx8025_init_client(client);     // 将设备操作函数rx8025_rtc_ops 和设备关联起来   rx8025->rtc = devm_rtc_device_register(&client->dev, client->name,                 &rx8025_rtc_ops, THIS_MODULE);      //irq?   if (client->irq > 0) {           //注册中断回调函数 rx8025_handle_irq      err = devm_request_threaded_irq(&client->dev, client->irq, NULL,                  rx8025_handle_irq,                  IRQF_ONESHOT,                  "rx8025", client);         }   rx8025->rtc->max_user_freq = 1;   /* the rx8025 alarm only supports a minute accuracy */   rx8025->rtc->uie_unsupported = 1;   err = rx8025_sysfs_register(&client->dev);   printk("%s  end\r\n", __func__);/*Herber*/   return err;}

这里重点关注 rx8025_rtc_ops,实现这里的读写函数就可以了。
static const struct rtc_class_ops rx8025_rtc_ops = {
.read_time = rx8025_get_time,
.set_time = rx8025_set_time,
.read_alarm = rx8025_read_alarm,
.set_alarm = rx8025_set_alarm,
.alarm_irq_enable = rx8025_alarm_irq_enable,
};

Struct rtc_class_ops 定义在rtc.h

struct rtc_class_ops {
int (*ioctl)(struct device *, unsigned int, unsigned long);
int (*read_time)(struct device *, struct rtc_time *);
int (*set_time)(struct device *, struct rtc_time *);
int (*read_alarm)(struct device *, struct rtc_wkalrm *);
int (*set_alarm)(struct device *, struct rtc_wkalrm *);
int (*proc)(struct device *, struct seq_file *);
int (*set_mmss64)(struct device *, time64_t secs);
int (*set_mmss)(struct device *, unsigned long secs);
int (*read_callback)(struct device *, int data);
int (*alarm_irq_enable)(struct device *, unsigned int enabled);
int (*read_offset)(struct device *, long *offset);
int (*set_offset)(struct device *, long offset);
};

这里分析下写入rtc寄存器

将dt的 tm_sec等,转成bcd码 写入RX8025_REG_SEC寄存器。

static int rx8025_set_time(struct device *dev, struct rtc_time *dt){   struct rx8025_data *rx8025 = dev_get_drvdata(dev);   u8 date[7];   int ret;   dump_stack();   printk("%s( %d %d %d %d %d %d %d %d %d)\n",__func__,dt->tm_sec,dt->tm_min,dt->tm_hour ,dt->tm_mday, dt->tm_mon,dt->tm_year, dt->tm_wday,dt->tm_yday,  dt->tm_isdst );   if ((dt->tm_year < 100) || (dt->tm_year > 199))   {        printk("%s set Year Err %d === \r\n",__func__,dt->tm_year);      return -EINVAL;   }   /*    * Here the read-only bits are written as "0".  I'm not sure if that    * is sound.    */   date[RX8025_REG_SEC] = bin2bcd(dt->tm_sec);   date[RX8025_REG_MIN] = bin2bcd(dt->tm_min);   if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)      date[RX8025_REG_HOUR] = bin2bcd(dt->tm_hour);   else      date[RX8025_REG_HOUR] = (dt->tm_hour >= 12 ? 0x20 : 0)         | bin2bcd((dt->tm_hour + 11) % 12 + 1);   date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday);   date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday);   date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1);   date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100);   ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date);   if (ret < 0)      return ret;   return rx8025_reset_validity(rx8025->client);                 }

下面是 读取rtc的寄存器

static int rx8025_get_time(struct device *dev, struct rtc_time *dt){   struct rx8025_data *rx8025 = dev_get_drvdata(dev);   u8 date[7];   int err;   dump_stack();   //从RX8025_REG_SEC 读7位到 date   err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date);   printk("%s para 0x%02x,0x%02x,0x%02x=== \r\n",__func__,date[0],date[1],date[2]);/*Herber*/   if (err){      printk("%s S3,Err +++++\r\n",__func__);      return err;   }      dt->tm_sec = bcd2bin(date[RX8025_REG_SEC] & 0x7f);   dt->tm_min = bcd2bin(date[RX8025_REG_MIN] & 0x7f);   if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224)      dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x3f);   else      dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x1f) % 12         + (date[RX8025_REG_HOUR] & 0x20 ? 12 : 0);   dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f);   dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1;   dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100;   dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__,      dt->tm_sec, dt->tm_min, dt->tm_hour,      dt->tm_mday, dt->tm_mon, dt->tm_year);   return rtc_valid_tm(dt);}

可以看到rtc 驱动只提供了简单的设定和读取年,月,日,星期,时,分,秒 时间信息的功能。

#define CFG_RTC_I2C_DEV              "/dev/rtc0" #include int main(void){   int fd_i2c,retval;   struct rtc_time new, current;   printf("==== RTC TIME operates ====\n");   fd_i2c = open(CFG_RTC_I2C_DEV, O_RDWR);             if (fd_i2c < 0) {      printf("Open i2c device %s failed!\n", CFG_RTC_I2C_DEV);      return -1;   }     scanf("%d-%d-%d", &new.tm_mday, &new.tm_mon, &new.tm_year);   printf("\r\n");   scanf("%d:%d:%d", &new.tm_hour, &new.tm_min, &new.tm_sec);   printf("\r\n");     printf("Test will set RTC date/time to %d-%d-%d, %02d:%02d:%02d.\n",   new.tm_mday, new.tm_mon + 1, new.tm_year + 1900,   new.tm_hour, new.tm_min, new.tm_sec);           /* Write the new date in RTC */  printf("renew data in RTC Module \r\n");   retval = ioctl(fd_i2c, RTC_SET_TIME, &new);   if (retval == -1) {      printf("--RTC_SET_TIME ioctl Err--\r\n");      //close(fd);        goto err;//exit(errno);   }   /* Read back */   retval = ioctl(fd_i2c, RTC_RD_TIME, &current);   if (retval == -1) {      printf("---RTC_RD_TIME ioctl Err ---\r\n");      goto err;exit(errno);   }         printf("\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",      current.tm_mday, current.tm_mon + 1, current.tm_year + 1900,      current.tm_hour, current.tm_min, current.tm_sec);  close(fd_i2c);   return 0;err:   if (fd_i2c)                                     close(fd_i2c);                      return -1;                    }

以上代码可以测试 rtc 的读写功能.

再梳理下rtc驱动的流程,在内核启动时 初始化rtc即rx8025_probe, 再将rtc 的时间给了系统。

static int __init rtc_hctosys(void){int err = -ENODEV;struct rtc_time tm;struct timespec64 tv64 = {.tv_nsec = NSEC_PER_SEC >> 1,};struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);err = rtc_read_time(rtc, &tm);tv64.tv_sec = rtc_tm_to_time64(&tm);err = do_settimeofday64(&tv64);dev_info(rtc->dev.parent,"setting system clock to ""%d-%02d-%02d %02d:%02d:%02d UTC (%lld)\n",tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec,(long long) tv64.tv_sec);return err;}late_initcall(rtc_hctosys);

这样系统时间就和rtc 的时间对齐了。

更多相关文章

  1. Android(安卓)中指纹识别
  2. INSTALL_FAILED_MISSING_FEATURE
  3. Android中GridView实现长按多选功能
  4. 用百度地图API实现Android定位功能(2.6版本为例)
  5. wifi 架构
  6. Android(安卓)记录一次开发微信分享功能的吐槽与思考
  7. Android(安卓)Browser 支持屏蔽webaudio的功能
  8. android debug工具集
  9. android分享软件功能的实现

随机推荐

  1. Android之获取本地图片并压缩方法
  2. 【android】让listview的顶部或者底部也
  3. Android 调用系统的邮箱app发送邮件
  4. android之Bundle
  5. 【Android Demo】获取指定网页的页面源代
  6. Android开源项目:捕鱼达人游戏源代码
  7. android databing数据绑定的简单使用
  8. Android自定义相机镂空遮罩
  9. [Android]LIstView的HeaderView
  10. Android Canvas和Paint