i.MX283 board standby mode wakeup

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

i.MX283 board standby mode wakeup

跳至解决方案
1,911 次查看
mallikarjunared
Contributor III

We need to implement Wakeup from stand by mode using RTC alarm on imx283 board. Can anybody provide some ideas in getting this  implemented?

标签 (1)
0 项奖励
回复
1 解答
1,440 次查看
mallikarjunared
Contributor III

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.

在原帖中查看解决方案

0 项奖励
回复
7 回复数
1,440 次查看
AnsonHuang
NXP Employee
NXP Employee

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;

0 项奖励
回复
1,440 次查看
mallikarjunared
Contributor III

Dear Yongcai Huang

                         wakealarm is not present in system. can you please tell me how to get it.

0 项奖励
回复
1,440 次查看
AnsonHuang
NXP Employee
NXP Employee

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 );

1,440 次查看
mallikarjunared
Contributor III

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

0 项奖励
回复
1,440 次查看
AnsonHuang
NXP Employee
NXP Employee

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.

0 项奖励
回复
1,441 次查看
mallikarjunared
Contributor III

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.

0 项奖励
回复
1,440 次查看
AnsonHuang
NXP Employee
NXP Employee

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>

0 项奖励
回复