[技术分享]Firefly-rk3288定时开机实现!

本帖最后由 Livvol 于 2016-7-13 17:47 编辑

如题,先上实现效果:
我板子上跑的是ubuntu 14.04系统。
查看下RTC硬件时钟的时间,如果与当前系统时间不符,那么将系统时间同步到RTC硬件时钟即可:

firefly@firefly:~$ sudo hwclock -r
Mon 11 Jul 2016 07:42:39 AM UTC  -0.432840 seconds
firefly@firefly:~$ sudo hwclock -w

给硬件时钟写入定时开机时间:

sudo ./on_off 2016.07.11.08.00.00

on_off 是一个简单的C程序,负责从节点/dev/alarm 给硬件时钟写入定时开机时间。

可以查看一下内核打印信息,看一下开机时间是否已经写进去:

firefly@firefly:~$ dmesg

[  364.964700] hym8563_rtc_set_alarm:diff_sec= 1007s , use alarm
[  364.967412] alarm_release: clear alarm, pending 0

如果出现上面信息,就说明开机时间已经顺利写进去,关机,然后静静等待,到时间后系统会自动启动,完美~。

接下来讲下实现方法,主要修改内核的两个个文件即可。ubuntu14.04 使用的内核版本跟Android 4.4的内核版本基本一致,可以利用我们的Android 4.4 SDK的内核来进行修改和编译。
首先需要修改:
kernel/drivers/rtc/rtc-HYM8563.c

@@ -25,6 +25,7 @@
#include “rtc-HYM8563.h”
#include <linux/of_gpio.h>
#include <linux/irqdomain.h>
+#include <linux/kernel.h>
#define RTC_SPEED 200 * 1000

struct hym8563 {

@@ -36,6 +37,7 @@ struct hym8563 {
struct wake_lock wake_lock;
};
static struct i2c_client *gClient = NULL;
+static struct hym8563 *g_hym8563 = NULL;

static int i2c_master_reg8_send(const struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate)
{

@@ -543,6 +546,7 @@ static int hym8563_probe(struct i2c_client *client, const struct i2c_device_id
int rc = 0;
u8 reg = 0;
struct hym8563 *hym8563;

  •   struct rtc_wkalrm alarm;
      struct rtc_device *rtc = NULL;
      struct rtc_time tm_read, tm = {
              .tm_wday = 6,
    

@@ -609,7 +613,8 @@ static int hym8563_probe(struct i2c_client *client, const struct i2c_device_id
goto exit;
}
hym8563->rtc = rtc;

  •   g_hym8563 = hym8563;
    
  •   hym8563_rtc_read_alarm(&gClient->dev,&alarm);
      return 0;
    

exit:

@@ -629,7 +634,7 @@ static int hym8563_remove(struct i2c_client *client)
}
-void hym8563_shutdown(struct i2c_client * client)
+/*void hym8563_shutdown(struct i2c_client * client)
{ u8 regs[2];
int ret;
//disable clkout

@@ -637,6 +642,28 @@ void hym8563_shutdown(struct i2c_client * client)
ret=hym8563_i2c_set_regs(client, RTC_CLKOUT, regs, 1);
if(ret<0)
printk(“rtc shutdown is error\n”);
+}*/
+static void hym8563_shutdown(struct i2c_client * client)
+{

  •   struct device *pdev = &client->dev;
    
  •   struct rtc_wkalrm alarm;
    
  •   struct rtc_device *rtc_dev = g_hym8563->rtc;
    
  •   u8 regs[4];
    
  •   rtc_read_alarm(rtc_dev,&alarm);
    
  •   if(alarm.enabled == 1){
    
  •           printk("%s this in shutdowm,the alarm.enabled = 1 \n",__func__);
    
  •   }
    
  •   hym8563_i2c_read_regs(client,RTC_CTL2,regs,1);
    
  •   regs[0] |= AIE;
    
  •   hym8563_i2c_set_regs(client, RTC_CTL2,regs,1);
    
  •   hym8563_i2c_read_regs(client,RTC_CTL2,regs,1);
    
  •   regs[0] |=TIE;
    
  •   hym8563_i2c_set_regs(client,RTC_CTL2,regs,1);
    
  •   hym8563_i2c_read_regs(client,RTC_CTL2,regs,1);
    

}

@@ -661,16 +688,19 @@ struct i2c_driver hym8563_driver = {
.probe = hym8563_probe,
.remove = hym8563_remove,
//.shutdown=hym8563_shutdown,

  •   .shutdown=hym8563_shutdown,
      .id_table       = hym8563_id,
    

};

接下来修改:
kernel/drivers/staging/android/alarm-dev.c

@@ -110,18 +110,35 @@ static void alarm_clear(enum android_alarm_type alarm_type)

}
static void alarm_set(enum android_alarm_type alarm_type,
struct timespec *ts)
{
uint32_t alarm_type_mask = 1U << alarm_type;
unsigned long flags;

  •   struct rtc_time time;
    
  •   struct rtc_device *rtc_dev;
    
  •   struct rtc_wkalrm alarm;
    
      spin_lock_irqsave(&alarm_slock, flags);
      alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
                      alarm_type, ts->tv_sec, ts->tv_nsec);
      alarm_enabled |= alarm_type_mask;
      devalarm_start(&alarms[alarm_type], timespec_to_ktime(*ts));
      spin_unlock_irqrestore(&alarm_slock, flags);
    
  •   if(alarm_type == 4){
    
  •    rtc_time_to_tm(ts->tv_sec,&time);
    
  •    rtc_dev = alarmtimer_get_rtcdev();
    
  •    alarm.time.tm_year = time.tm_year;
    
  •    alarm.time.tm_mon = time.tm_mon;
    
  •    alarm.time.tm_mday = time.tm_mday;
    
  •    alarm.time.tm_wday = time.tm_wday;
    
  •    alarm.time.tm_hour = time.tm_hour;
    
  •    alarm.time.tm_min = time.tm_min;
    
  •    alarm.time.tm_sec = time.tm_sec;
    
  •    alarm.enabled = 1;
    
  •    rtc_set_alarm(rtc_dev,&alarm);
    
  •    }
    

}

static int alarm_wait(void)

以上是我从整理好的patch里面搬下来的,有点乱。大家改的时候耐心点,别看错:P~以上两个文件修改完后,编译好内核,并烧到板子上即可。
修改好的这两个文件我已上传,见附件。

然后,就可以写个简单的C程序,来验证下修改是否有效啦。
以下为代码的部分内容,其余大家可以自行发挥编辑,我就不贴上来了:

#define type_4 1074291010

fd = open("/dev/alarm", O_RDWR);
    if(fd < 0) {
        printf("Unable to open alarm driver: %s\n", strerror(errno));
        return -1;
    }
    ts.ts_sec = (int)timep;
    ts.ts_nsec =0;
    res = ioctl(fd,type_4,&ts);
    if(res < 0) {
        printf("Unable to set rtc to %ld: %s\n", ts.ts_sec, strerror(errno));
        close(fd);
        return 0;
    }

以上为Firefly-rk3288定时开机的基本实现!:victory:,如有不妥的地方,欢迎大家来吐槽:lol。
有定时开机就有定时关机,至于定时关机,比较简单的思路是写个程序循环判定设置的时间是否与当前时间相等,相等就调用系统指令poweroff关机即可。大家可以试试~


ScheduledPowerOn.tar.gz (7.3 KB)

学习 。。

好贴,加精支持!

厉害,学习,学习

有人试过没有~~~

abcxyztt 发表于 2016-8-15 13:50
在Android层就可以实现 定时开关

这是ubuntu哦,另外在android下实现定时开机也需要底层驱动支持的。

学习,学习

ohyeah521 发表于 2016-10-20 12:13
板子断电后在加电,硬件时钟还是会变,怎么办?要加纽扣电池吗 ?

对,断电后再加电,时钟是会回复为默认时间的,这个只能加电池了

ohyeah521 发表于 2016-10-21 18:59
怎么加?求一个教程,不知道能不能写的详细点,我看群里也有几个朋友问如何添加rtc的问题。
还需要采购 …

加电池要修改电路的,我自己没改过^_^!。官方reload板子就有做RTC电池接口,官网应该有放出来原理图,你找一下,可以做个参考。

你好,能否分享一下demo源码,感谢

shh ° 发表于 2016-11-22 19:39
你好,能否分享一下demo源码,感谢

我写的demo程序只是一个简单的c程序啦,就是一些简单的文件操作,核心的几步我已经贴出来了,参照着来写就行了。

abcxyztt 发表于 2016-8-15 13:50
在Android层就可以实现 定时开关

你好,怎么样在android实现定时开关机,能否指导下?

为何是 hym8563?

哪位大神可以分享一下 楼主的代码吗? 我等级不够 下不了

mahaoran 发表于 2018-12-5 10:12
哪位大神可以分享一下 楼主的代码吗? 我等级不够 下不了

我分享给你 哈哈哈哈哈哈哈

参考参考~

为什么下不了

{:4_123:}

正好现在需要用到,来学习学习