2014-06-17 13:41:14 +00:00
# include <stdbool.h>
# include <avr/sleep.h>
# include <avr/wdt.h>
# include <avr/interrupt.h>
2013-03-24 16:46:32 +00:00
# include "matrix.h"
# include "action.h"
2013-05-30 18:24:39 +00:00
# include "backlight.h"
2014-06-17 13:41:14 +00:00
# include "suspend_avr.h"
# include "suspend.h"
2014-11-26 02:25:45 +00:00
# include "timer.h"
2014-11-20 08:06:46 +00:00
# ifdef PROTOCOL_LUFA
# include "lufa.h"
# endif
2014-06-17 13:41:14 +00:00
# define wdt_intr_enable(value) \
__asm__ __volatile__ ( \
" in __tmp_reg__,__SREG__ " " \n \t " \
" cli " " \n \t " \
" wdr " " \n \t " \
" sts %0,%1 " " \n \t " \
" out __SREG__,__tmp_reg__ " " \n \t " \
" sts %0,%2 " " \n \t " \
: /* no outputs */ \
: " M " ( _SFR_MEM_ADDR ( _WD_CONTROL_REG ) ) , \
" r " ( _BV ( _WD_CHANGE_BIT ) | _BV ( WDE ) ) , \
" r " ( ( uint8_t ) ( ( value & 0x08 ? _WD_PS3_MASK : 0x00 ) | \
_BV ( WDIE ) | ( value & 0x07 ) ) ) \
: " r0 " \
)
2013-03-24 16:46:32 +00:00
2014-11-20 08:06:46 +00:00
void suspend_idle ( uint8_t time )
2013-03-24 16:46:32 +00:00
{
cli ( ) ;
2014-11-20 08:06:46 +00:00
set_sleep_mode ( SLEEP_MODE_IDLE ) ;
sleep_enable ( ) ;
sei ( ) ;
sleep_cpu ( ) ;
sleep_disable ( ) ;
}
/* Power down MCU with watchdog timer
* wdto : watchdog timer timeout defined in < avr / wdt . h >
* WDTO_15MS
* WDTO_30MS
* WDTO_60MS
* WDTO_120MS
* WDTO_250MS
* WDTO_500MS
* WDTO_1S
* WDTO_2S
* WDTO_4S
* WDTO_8S
*/
2014-11-26 02:25:45 +00:00
static uint8_t wdt_timeout = 0 ;
static void power_down ( uint8_t wdto )
2014-11-20 08:06:46 +00:00
{
# ifdef PROTOCOL_LUFA
if ( USB_DeviceState = = DEVICE_STATE_Configured ) return ;
# endif
2014-11-26 02:25:45 +00:00
wdt_timeout = wdto ;
2013-03-24 16:46:32 +00:00
// Watchdog Interrupt Mode
2014-11-20 08:06:46 +00:00
wdt_intr_enable ( wdto ) ;
2013-03-24 16:46:32 +00:00
// TODO: more power saving
// See PicoPower application note
// - I/O port input with pullup
// - prescale clock
// - BOD disable
// - Power Reduction Register PRR
set_sleep_mode ( SLEEP_MODE_PWR_DOWN ) ;
sleep_enable ( ) ;
sei ( ) ;
sleep_cpu ( ) ;
sleep_disable ( ) ;
// Disable watchdog after sleep
wdt_disable ( ) ;
}
2014-11-26 02:25:45 +00:00
void suspend_power_down ( void )
{
power_down ( WDTO_15MS ) ;
}
2013-03-24 16:46:32 +00:00
bool suspend_wakeup_condition ( void )
{
2014-11-20 08:06:46 +00:00
matrix_power_up ( ) ;
2013-03-24 16:46:32 +00:00
matrix_scan ( ) ;
2014-11-20 08:06:46 +00:00
matrix_power_down ( ) ;
2013-03-24 16:46:32 +00:00
for ( uint8_t r = 0 ; r < MATRIX_ROWS ; r + + ) {
if ( matrix_get_row ( r ) ) return true ;
}
return false ;
}
2013-03-26 07:55:45 +00:00
// run immediately after wakeup
2013-03-24 16:46:32 +00:00
void suspend_wakeup_init ( void )
{
2013-09-21 13:47:03 +00:00
// clear keyboard state
2013-03-24 16:46:32 +00:00
clear_keyboard ( ) ;
2013-05-30 18:24:39 +00:00
# ifdef BACKLIGHT_ENABLE
backlight_init ( ) ;
# endif
2013-03-24 16:46:32 +00:00
}
2013-03-26 07:55:45 +00:00
# ifndef NO_SUSPEND_POWER_DOWN
/* watchdog timeout */
ISR ( WDT_vect )
{
2014-11-26 02:25:45 +00:00
// compensate timer for sleep
switch ( wdt_timeout ) {
case WDTO_15MS :
timer_count + = 15 + 2 ; // WDTO_15MS + 2(from observation)
break ;
default :
;
2013-03-26 07:55:45 +00:00
}
}
# endif