We need to implement Wakeup from stand by mode using RTC alarm on imx283 board. Can anybody provide some ideas in getting this implemented?
解決済! 解決策の投稿を見る。
Dear Yongcai,
It is working fine. Here is the code which I used for setting alarm.
#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
main()
{
int i, fd, retval, irqcount = 0;
unsigned long tmp, data;
struct rtc_time rtc_tm;
fd = open(/dev/rtc0, O_RDONLY);
if (fd == -1)
{
//return error
}
fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n");
/* Read the RTC time/date */
retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
if (retval == -1)
{
//return error
}
fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
/* Set the alarm to 3 sec in the future, and check for rollover */
rtc_tm.tm_sec += 3;
if (rtc_tm.tm_sec >= 60)
{
rtc_tm.tm_sec %= 60;
rtc_tm.tm_min++;
}
if (rtc_tm.tm_min == 60)
{
rtc_tm.tm_min = 0;
rtc_tm.tm_hour++;
}
if (rtc_tm.tm_hour == 24)
rtc_tm.tm_hour = 0;
retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
if (retval == -1)
{
if (errno == ENOTTY)
{
fprintf(stderr,
"\n...Alarm IRQs not supported.\n");
// goto test_PIE; for test
}
perror("RTC_ALM_SET ioctl");
exit(errno);
}
/* Read the current alarm settings */
retval = ioctl(fd, RTC_ALM_READ, &rtc_tm);
if (retval == -1)
{
perror("RTC_ALM_READ ioctl");
exit(errno);
}
fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n",
rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
/* Enable alarm interrupts */
retval = ioctl(fd, RTC_AIE_ON, 0);
if (retval == -1)
{
perror("RTC_AIE_ON ioctl");
exit(errno);
}
fprintf(stderr, "Waiting 3 seconds for alarm...");
fflush(stderr);
/* This blocks until the alarm ring causes an interrupt */
retval = read(fd, &data, sizeof(unsigned long));
if (retval == -1)
{
perror("read");
exit(errno);
}
irqcount++;
fprintf(stderr, " okay. Alarm rang.\n");
/* Disable alarm interrupts */
retval = ioctl(fd, RTC_AIE_OFF, 0);
if (retval == -1)
{
perror("RTC_AIE_OFF ioctl");
exit(errno);
}
close(fd);
}
For going to suspend mode
echo standby > /sys/power/state
Note :
Run alarm as saparete thread or in background
If any issues let me know.
Hi, Mallikarjuna
Can you try below command, if RTC driver is working, then system should be wakeup after 10 seconds.
echo +10 > /sys/class/rtc/rtc0/wakealarm;
echo standby > /sys/power/state;
Dear Yongcai Huang
wakealarm is not present in system. can you please tell me how to get it.
Hi, Mallikarjuna
Maybe the rtc driver is not supporting this feature on old kernel, I remembered that we have a customer that use RTC alarm to wakeup system every second to check some info, I have the interface pasted as below, you can try it.
static void icoll_mask_irq(unsigned int irq)
{
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
IO_ADDRESS(ICOLL_PHYS_ADDR) + HW_ICOLL_INTERRUPTn_CLR(irq));
}
static void icoll_unmask_irq(unsigned int irq)
{
__raw_writel(BM_ICOLL_INTERRUPTn_ENABLE,
IO_ADDRESS(ICOLL_PHYS_ADDR) + HW_ICOLL_INTERRUPTn_SET(irq));
}
static int set_rtc_alarm(unsigned int time)
{
unsigned int counter;
counter = __raw_readl( IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_SECONDS );
counter += time;
__raw_writel(counter, IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_ALARM);
return 0;
}
static int rtc_ioctl( unsigned int cmd)
{
switch (cmd)
{
case RTC_AIE_OFF:
__raw_writel(BM_RTC_PERSISTENT0_ALARM_EN |
BM_RTC_PERSISTENT0_ALARM_WAKE_EN,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_PERSISTENT0_CLR);
__raw_writel(BM_RTC_CTRL_ALARM_IRQ_EN,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL_CLR);
break;
case RTC_AIE_ON:
__raw_writel(BM_RTC_PERSISTENT0_ALARM_EN |
BM_RTC_PERSISTENT0_ALARM_WAKE_EN,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_PERSISTENT0_SET);
__raw_writel(BM_RTC_CTRL_ALARM_IRQ_EN,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL_SET);
break;
case RTC_UIE_ON:
__raw_writel(BM_RTC_CTRL_ONEMSEC_IRQ_EN,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL_SET);
break;
case RTC_UIE_OFF:
__raw_writel(BM_RTC_CTRL_ONEMSEC_IRQ_EN,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL_CLR);
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
static void wakeup_irq_ack(unsigned int irq)
{
__raw_writel(0, IO_ADDRESS(ICOLL_PHYS_ADDR) + HW_ICOLL_VECTOR);
__raw_writel(BV_ICOLL_LEVELACK_IRQLEVELACK__LEVEL0,
IO_ADDRESS(ICOLL_PHYS_ADDR) + HW_ICOLL_LEVELACK);
}
static int wakeup_Irq_query( int WakeIrqVector )
{
int IsRtcAlarm = 0;
switch( WakeIrqVector )
{
case IRQ_RTC_ALARM:
if( __raw_readl( IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL ) )
{
__raw_writel( BM_RTC_CTRL_ALARM_IRQ,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL_CLR );
IsRtcAlarm = 1;
}
ap_wakeup_irq_ack( WakeIrqVector );
break;
/*****************************************************/
default:
ap_wakeup_irq_ack( WakeIrqVector );
if( __raw_readl( IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL ) )
{
__raw_writel( BM_RTC_CTRL_ALARM_IRQ,
IO_ADDRESS( RTC_PHYS_ADDR ) + HW_RTC_CTRL_CLR );
IsRtcAlarm = 1;
}
break;
// default: break;
}
return IsRtcAlarm;
}
The basic flow is to set rtc alarm's time, then config RTC to enable alarm, then unmask interrupt controller. To disable it, need to disable RTC alarm and mask its interrupt:
set_rtc_alarm( 1 );
rtc_ioctl( RTC_AIE_ON );
icoll_unmask_irq( IRQ_RTC_ALARM );
/*need to ack rtc irq if alarm happened*/
wakeup_irq_ack( WakeIrqVector );
rtc_ioctl( RTC_AIE_OFF );
icoll_mask_irq( IRQ_RTC_ALARM );
Dear Yongcai,
Thanks for your answer. I didn't tried this exactly, but I followed below steps.
ioctl calls
Read RTC Time - RTC_RD_TIME
Set Alarm - RTC_ALM_SET
Enable Alarm Interrupts - RTC_AIE_ON
Disable Alarm Interrupts after alarm rang - RTC_AIE_OFF
Hi, Mallikarjuna
So does it work? Sorry that I did NOT have a i.MX28 EVK board here, so I can NOT try it for you, just provide my idea.
Dear Yongcai,
It is working fine. Here is the code which I used for setting alarm.
#include <stdio.h>
#include <linux/rtc.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
main()
{
int i, fd, retval, irqcount = 0;
unsigned long tmp, data;
struct rtc_time rtc_tm;
fd = open(/dev/rtc0, O_RDONLY);
if (fd == -1)
{
//return error
}
fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n");
/* Read the RTC time/date */
retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
if (retval == -1)
{
//return error
}
fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
/* Set the alarm to 3 sec in the future, and check for rollover */
rtc_tm.tm_sec += 3;
if (rtc_tm.tm_sec >= 60)
{
rtc_tm.tm_sec %= 60;
rtc_tm.tm_min++;
}
if (rtc_tm.tm_min == 60)
{
rtc_tm.tm_min = 0;
rtc_tm.tm_hour++;
}
if (rtc_tm.tm_hour == 24)
rtc_tm.tm_hour = 0;
retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
if (retval == -1)
{
if (errno == ENOTTY)
{
fprintf(stderr,
"\n...Alarm IRQs not supported.\n");
// goto test_PIE; for test
}
perror("RTC_ALM_SET ioctl");
exit(errno);
}
/* Read the current alarm settings */
retval = ioctl(fd, RTC_ALM_READ, &rtc_tm);
if (retval == -1)
{
perror("RTC_ALM_READ ioctl");
exit(errno);
}
fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n",
rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
/* Enable alarm interrupts */
retval = ioctl(fd, RTC_AIE_ON, 0);
if (retval == -1)
{
perror("RTC_AIE_ON ioctl");
exit(errno);
}
fprintf(stderr, "Waiting 3 seconds for alarm...");
fflush(stderr);
/* This blocks until the alarm ring causes an interrupt */
retval = read(fd, &data, sizeof(unsigned long));
if (retval == -1)
{
perror("read");
exit(errno);
}
irqcount++;
fprintf(stderr, " okay. Alarm rang.\n");
/* Disable alarm interrupts */
retval = ioctl(fd, RTC_AIE_OFF, 0);
if (retval == -1)
{
perror("RTC_AIE_OFF ioctl");
exit(errno);
}
close(fd);
}
For going to suspend mode
echo standby > /sys/power/state
Note :
Run alarm as saparete thread or in background
If any issues let me know.
I am glad to here that it is working, can you please check the correct answer and close this topic? thanks in advanced!
Sent from Anson's iPhone
? 2014?1?2??22:10?"Mallikarjuna Reddy" <admin@community.freescale.com<mailto:admin@community.freescale.com>> ???
<https://community.freescale.com/>
<https://community.freescale.com/>
i.MX283 board standby mode wakeup
reply from Mallikarjuna Reddy<https://community.freescale.com/people/mallikarjunareddy?et=watches.email.thread> in i.MX Community - View the full discussion<https://community.freescale.com/message/371070?et=watches.email.thread#371070>