版型
补丁
附件是以rk808为例实现的,使用rk809思路是一样的:
1.在底层做一个独立的alarm接口(本patch中是提供的接口为rk808_rtc_setalarm_pwron),上层设定开机时间;
2.上层设置的时间会调到该接口,然后保存开机时间;
3.等到真正关机时,在关机函数里将rtc/alarm中断全部打开,并将开机时间写进alarm寄存器;
4.一旦到达设定的时间,rtc通过唤醒pmu达到给整个系统上电的效果;
5.定时关机的功能比较简单,自己根据需求调用关机函数即可,不在赘述;
附件是以4.4kernel的rk808为例实现的,上层只需通过ioctl方法往接口里写入开机时间,
具体的应用程序可以参考“测试应用程序”,如有问题记得用串口抓完整的关机log;
- --- a/drivers/mfd/rk808.c
- +++ b/drivers/mfd/rk808.c
- @@ -61,7 +61,7 @@ static struct mfd_cell rk808s[] = {
- #define VOL_MIN_IDX 0x00
- #define VOL_MAX_IDX 0x3f
- -
- +static int getalarm[6];
- const static int buck_set_vol_base_addr[] = {
- RK808_BUCK1_ON_REG,
- RK808_BUCK2_ON_REG,
- @@ -1017,6 +1017,31 @@ static ssize_t rk808_test_show(struct kobject *kobj, struct kobj_attribute *attr
- }
- +static ssize_t rk808_alarm_store(struct kobject *kobj, struct kobj_attribute *attr,
- + const char *buf, size_t n)
- +{
- + char cmd;
- + const char *buftmp = buf;
- +
- + sscanf(buftmp, "%x%c%x%c%x%c%x%c%x%c%x", &getalarm[5],&cmd,&getalarm[4],&cmd,&getalarm[3],
- + &cmd,&getalarm[2],&cmd,&getalarm[1],&cmd,&getalarm[0]);
- + printk("xiong: get year = %xn", getalarm[5]);
- + printk("xiong: get mon = %xn", getalarm[4]);
- + printk("xiong: get day = %xn", getalarm[3]);
- + printk("xiong: get hour = %xn", getalarm[2]);
- + printk("xiong: get min = %xn", getalarm[1]);
- + printk("xiong: get sec = %xn", getalarm[0]);
- + return n;
- +
- +}
- +
- +static ssize_t rk808_alarm_show(struct kobject *kobj, struct kobj_attribute *attr,
- + char *buf)
- +{
- + return sprintf(buf, "%x%c%x%c%x%c%x%c%x%c%xn", getalarm[5], '_', getalarm[4], '_', getalarm[3],
- + '_', getalarm[2], '_', getalarm[1], '_', getalarm[0]);
- +}
- +
- static struct kobject *rk808_kobj;
- struct rk808_attribute {
- struct attribute attr;
- @@ -1029,6 +1054,7 @@ struct rk808_attribute {
- static struct rk808_attribute rk808_attrs[] = {
- /* node_name permision show_func store_func */
- __ATTR(rk808_test, S_IRUGO | S_IWUSR, rk808_test_show, rk808_test_store),
- + __ATTR(rk808_alarm, S_IRUGO | S_IWUSR, rk808_alarm_show, rk808_alarm_store),
- };
- #endif
- #if 0
- @@ -1141,8 +1167,10 @@ static void rk808_shutdown(void)
- printk("%s,line=%d dc[%d]= %dn", __func__,__LINE__,(i+1),val);
- }
- /*****************************************************/
- - ret = rk808_set_bits(rk808, RK808_INT_STS_MSK_REG1,(0x3<<5),(0x3<<5)); //close rtc int when power off
- - ret = rk808_clear_bits(rk808, RK808_RTC_INT_REG,(0x3<<2)); //close rtc int when power off
- + //ret = rk808_set_bits(rk808, RK808_INT_STS_MSK_REG1,(0x3<<5),(0x3<<5)); //close rtc int when power off
- + //ret = rk808_clear_bits(rk808, RK808_RTC_INT_REG,(0x3<<2)); //close rtc int when power off
- + ret = rk808_clear_bits(rk808, RK808_INT_STS_MSK_REG1,(0x3<<5)); //open rtc int when power on
- + ret = rk808_set_bits(rk808, RK808_RTC_INT_REG,(0x1<<3),(0x1<<3)); //open rtc int when power on
- mutex_lock(&rk808->io_lock);
- mdelay(100);
- }
- @@ -1153,9 +1181,23 @@ static struct syscore_ops rk808_syscore_ops = {
- static void rk808_device_shutdown(void)
- {
- - int ret,i;
- + int ret,i,j;
- u8 reg = 0;
- struct rk808 *rk808 = g_rk808;
- +
- + for(j=0x0d; j>=0x08; j--)
- + {
- + ret = rk808_i2c_write(rk808, j, 1,getalarm[j-8]);
- + if (ret <0)
- + printk("write alarm reg error!n");
- + }
- + for (j = 0; j < 0x13; j++)
- + {
- + ret=rk808_i2c_read(rk808,j,1,®);
- + if (ret <0)
- + printk("read rtc & alarm reg error!n");
- + printk("reg[0x%x]:%xn",j,reg);
- + }
- for(i=0;i < 10;i++){
- printk("%sn",__func__);
- ret = rk808_i2c_read(rk808,RK808_DEVCTRL_REG,1,®);
- @@ -1169,6 +1211,7 @@ static void rk808_device_shutdown(void)
- }
- while(1)wfi();
- }
- +
- EXPORT_SYMBOL_GPL(rk808_device_shutdown);
- __weak void rk808_device_suspend(void) {}
复制代码
测试方法:
用adb或者串口都行 su echo +60 > /sys/class/rtc/rtc0/wakealarm cat /sys/class/rtc/rtc0/wakealarm reboot -p 关机之后等60S系统自动开机了,验证成功
|