Livvol 发表于 2016-7-11 17:39:25

[技术分享]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.00on_off 是一个简单的C程序,负责从节点/dev/alarm 给硬件时钟写入定时开机时间。

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

hym8563_rtc_set_alarm:diff_sec= 1007s , use alarm
alarm_release: clear alarm, pending 0如果出现上面信息,就说明开机时间已经顺利写进去,关机,然后静静等待,到时间后系统会自动启动,完美~。

static/image/hrline/5.gif

接下来讲下实现方法,主要修改内核的两个个文件即可。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 inthym8563_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 inthym8563_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 inthym8563_remove(struct i2c_client *client)
}
-void hym8563_shutdown(struct i2c_client * client)
+/*void hym8563_shutdown(struct i2c_client * client)
{      u8 regs;
   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;
+      
+       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 |= AIE;
+       hym8563_i2c_set_regs(client, RTC_CTL2,regs,1);
+       hym8563_i2c_read_regs(client,RTC_CTL2,regs,1);
+      
+       regs |=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, 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~以上两个文件修改完后,编译好内核,并烧到板子上即可。
修改好的这两个文件我已上传,见附件。

static/image/hrline/5.gif


然后,就可以写个简单的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关机即可。大家可以试试~

static/image/hrline/5.gif


loading 发表于 2016-7-11 18:10:16

学习 。。

暴走的阿Sai 发表于 2016-7-12 11:57:28

好贴,加精支持!

lam007 发表于 2016-8-10 14:13:29

厉害,学习,学习

zhang7013409 发表于 2016-8-11 22:12:07

有人试过没有~~~

Livvol 发表于 2016-8-15 14:43:38

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

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

qu-qu 发表于 2016-8-23 12:29:37

学习,学习

ohyeah521 发表于 2016-10-20 12:13:27

板子断电后在加电,硬件时钟还是会变,怎么办?要加纽扣电池吗 ?

Livvol 发表于 2016-10-21 15:21:18

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

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

ohyeah521 发表于 2016-10-21 18:59:57

Livvol 发表于 2016-10-21 15:21
对,断电后再加电,时钟是会回复为默认时间的,这个只能加电池了

怎么加?求一个教程,不知道能不能写的详细点,我看群里也有几个朋友问如何添加rtc的问题。
还需要采购什么东西?方便的话,给个你买的淘宝链接。谢谢。
页: [1] 2 3
查看完整版本: [技术分享]Firefly-rk3288定时开机实现!