void jz_hibernate(void) { local_irq_disable(); #ifdef CONFIG_BOARD_H600S poweroff_inand(); #endif /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); /* Set reset pin low-level assertion time after wakeup: must > 60ms */ rtc_write_reg(RTC_HRCR, (3 << 11)); /* clear wakeup status register */ rtc_write_reg(RTC_HWRSR, 0x0); rtc_write_reg(RTC_HWCR, 0x8); while(1) { /* Put CPU to hibernate mode */ rtc_write_reg(RTC_HCR, 0x1); jz_notifier_call(NOTEFY_PROI_HIGH, JZ_POST_HIBERNATION, NULL); mdelay(200); printk("We should NOT come here.%08x\n",inl(RTC_IOBASE + RTC_HCR)); } }
void alarm_disable(struct sunxi_rtc *rtc_dev) { int reg_val = 0; /* disable alarm irq */ rtc_write_reg(rtc_dev->ac100, ALM_INT_ENA_OFF, 0); /* clear alarm irq pending */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_INT_STA_REG_OFF); if (reg_val & 1) { pr_err("%s(%d) maybe err: alarm irq pending is set, clear it! reg is 0x%x\n", __func__, __LINE__, reg_val); rtc_write_reg(rtc_dev->ac100, ALM_INT_STA_REG_OFF, 1); } #ifdef CONFIG_ARCH_SUN8IW6P1 /* * shutdown alarm need alarm interrupt enable info when system startup, but * the info be cleared in u-boot boot process for a problem. so store the * info to RTC_GP_REG_N_OFF reg. * */ reg_val = rtc_read_reg(rtc_dev->ac100, RTC_GP_REG_N_OFF); reg_val &= ~0x1; rtc_write_reg(rtc_dev->ac100, RTC_GP_REG_N_OFF, reg_val); #endif }
/// initialise the RTC subsystem void rtc_init(void) { // unlock the RTC RTC0KEY = 0xa5; RTC0KEY = 0xf1; // configure for self-oscillation rtc_write_reg(RTC_PIN, RTC_PIN_SELF_OSC); // double the clock rate rtc_write_reg(RTC_XCN, RTC_XCN_BIASX2); // start it running rtc_write_reg(RTC_CN, CN_RUN); }
/// return the RTC timer as a 16 bit value. /// /// @return The RTC clock in 25usec units /// /// Note: this call takes about 50usec uint16_t rtc_read_count16(void) { uint16_t ret; EX0_SAVE_DISABLE; // start a capture rtc_write_reg(RTC_CN, CN_CAPTURE); // wait for capture to complete while (rtc_read_reg(RTC_CN) & RTC_CN_CAP) ; // capture the current counter value registers // using a auto-incrementing strobe read RTC0ADR = RTC0ADR_BUSY | RTC0ADR_AUTO | RTC0ADR_SHORT; __asm NOP NOP NOP __endasm; ret = RTC0DAT; __asm NOP NOP NOP __endasm; ret |= (RTC0DAT<<8); EX0_RESTORE; return ret; }
static void alarm_irq_work(struct work_struct *work) { struct sunxi_rtc *rtc_dev = container_of(work, struct sunxi_rtc, work); int reg_val; mutex_lock(&rtc_dev->mutex); /* clear alarm irq pending */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_INT_STA_REG_OFF); if (reg_val < 0) { mutex_unlock(&rtc_dev->mutex); pr_err("%s(%d) err: read alarm int status reg failed!\n", __func__, __LINE__); goto end; } if (reg_val & 1) { rtc_write_reg(rtc_dev->ac100, ALM_INT_STA_REG_OFF, 1); mutex_unlock(&rtc_dev->mutex); pr_err("%s(%d): alarm interrupt!\n", __func__, __LINE__); rtc_update_irq(rtc_dev->rtc, 1, RTC_AF | RTC_IRQF); goto end; } mutex_unlock(&rtc_dev->mutex); end: arisc_enable_nmi_irq(); }
void sunxi_rtc_hw_init(struct sunxi_rtc *rtc_dev) { int reg_val; /* reset rtc reg??? */ /* set 24h mode */ rtc_write_reg(rtc_dev->ac100, RTC_CTRL_REG_OFF, RTC_12H_24H_MODE); /* disable alarm irq remove to after rtc_device_register() */ // rtc_write_reg(rtc_dev->ac100, ALM_INT_ENA_OFF, 0); /* clear alarm irq pending */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_INT_STA_REG_OFF); if (!IS_ERR_VALUE(reg_val) && (reg_val & 1)) rtc_write_reg(rtc_dev->ac100, ALM_INT_STA_REG_OFF, 1); }
static int alarm_settime(struct sunxi_rtc *rtc_dev, struct rtc_time *tm) { int actual_year, actual_month, reg_val; actual_year = tm->tm_year + 1900; /* tm_year is from 1900 in linux */ actual_month = tm->tm_mon + 1; /* month is 1..12 in RTC reg but 0..11 in linux */ pr_info("%s(%d): time to set %d-%d-%d %d:%d:%d\n", __func__, __LINE__, actual_year, actual_month, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); /* set sec */ reg_val = bin2bcd(tm->tm_sec) & 0x7f; reg_val |= ALM_SEC_ENA_FLAG; rtc_write_reg(rtc_dev->ac100, ALM_SEC_REG_OFF, reg_val); /* set minute */ reg_val = bin2bcd(tm->tm_min) & 0x7f; reg_val |= ALM_MIN_ENA_FLAG; rtc_write_reg(rtc_dev->ac100, ALM_MIN_REG_OFF, reg_val); /* set hour */ reg_val = bin2bcd(tm->tm_hour) & 0x3f; reg_val |= ALM_HOU_ENA_FLAG; rtc_write_reg(rtc_dev->ac100, ALM_HOU_REG_OFF, reg_val); /* set week */ reg_val = bin2bcd(tm->tm_wday) & 0x7; #if 0 /* donot both enable day & week alarm */ reg_val |= ALM_WEE_ENA_FLAG; #endif rtc_write_reg(rtc_dev->ac100, ALM_WEEK_REG_OFF, reg_val); /* set day */ reg_val = bin2bcd(tm->tm_mday) & 0x3f; reg_val |= ALM_DAY_ENA_FLAG; rtc_write_reg(rtc_dev->ac100, ALM_DAY_REG_OFF, reg_val); /* set month */ reg_val = bin2bcd(actual_month) & 0x1f; reg_val |= ALM_MON_ENA_FLAG; rtc_write_reg(rtc_dev->ac100, ALM_MON_REG_OFF, reg_val); /* set year */ reg_val = actual_year_to_reg_year(actual_year); reg_val = bin2bcd(reg_val) & 0xff; reg_val |= ALM_YEA_ENA_FLAG; rtc_write_reg(rtc_dev->ac100, ALM_YEA_REG_OFF, reg_val); /* set write trig bit */ rtc_write_reg(rtc_dev->ac100, ALM_UPD_TRIG_OFF, ALM_WRITE_RTIG_FLAG); mdelay(30); /* delay 30ms to wait stable */ pr_info("%s(%d): set alarm time %d-%d-%d %d:%d:%d success!\n", __func__, __LINE__, actual_year, actual_month, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; }
static int rtc_settime(struct sunxi_rtc *rtc_dev, struct rtc_time *tm) { int actual_year, actual_month, leap_year = 0, reg_val; actual_year = tm->tm_year + 1900; /* tm_year is from 1900 in linux */ actual_month = tm->tm_mon + 1; /* month is 1..12 in RTC reg but 0..11 in linux */ leap_year = IS_LEAP_YEAR(actual_year); pr_info("%s(%d): time to set %d-%d-%d %d:%d:%d\n", __func__, __LINE__, actual_year, actual_month, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); /* prevent the application seting the error time */ if (!time_valid(tm)) { #if 1 pr_err("%s(%d) err: date %d-%d-%d %d:%d:%d invalid!\n", __func__, __LINE__, actual_year, actual_month, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return -EINVAL; #else pr_info("%s(%d) err: date %d-%d-%d %d:%d:%d invalid, so reset to 1970-1-1 00:00:00\n", __func__, __LINE__, actual_year, actual_month, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; tm->tm_mday = 0; tm->tm_mon = 0; /* 0 is month 1(January) */ tm->tm_year = 70; /* tm_year=0 is 1900, so tm_year=70 is 1970 */ actual_year = tm->tm_year + 1900; /* refresh actual_year for actual_year_to_reg_year below */ actual_month = tm->tm_mon + 1; /* refresh actual_month for below */ leap_year = IS_LEAP_YEAR(actual_year); /* refresh leap_year flag for below */ #endif } /* set time */ rtc_write_reg(rtc_dev->ac100, RTC_SEC_REG_OFF, bin2bcd(tm->tm_sec) & 0x7f); rtc_write_reg(rtc_dev->ac100, RTC_MIN_REG_OFF, bin2bcd(tm->tm_min) & 0x7f); rtc_write_reg(rtc_dev->ac100, RTC_HOU_REG_OFF, bin2bcd(tm->tm_hour) & 0x3f); rtc_write_reg(rtc_dev->ac100, RTC_WEE_REG_OFF, bin2bcd(tm->tm_wday) & 0x7); rtc_write_reg(rtc_dev->ac100, RTC_DAY_REG_OFF, bin2bcd(tm->tm_mday) & 0x3f); rtc_write_reg(rtc_dev->ac100, RTC_MON_REG_OFF, bin2bcd(actual_month) & 0x1f); /* set year */ reg_val = actual_year_to_reg_year(actual_year); reg_val = bin2bcd(reg_val) & 0xff; if (leap_year) reg_val |= LEAP_YEAR_FLAG; rtc_write_reg(rtc_dev->ac100, RTC_YEA_REG_OFF, reg_val); /* set write trig bit */ rtc_write_reg(rtc_dev->ac100, RTC_UPD_TRIG_OFF, RTC_WRITE_RTIG_FLAG); mdelay(30); /* delay 30ms to wait write stable */ pr_info("%s(%d): set time %d-%d-%d %d:%d:%d success!\n", __func__, __LINE__, actual_year, actual_month, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return 0; }
static int __init sunxi_rtc_probe(struct platform_device *pdev) { struct sunxi_rtc *rtc_dev; int err = 0; #ifdef CONFIG_ARCH_SUN8IW6P1 int reg_val = 0; #endif pr_debug("%s,line:%d\n", __func__, __LINE__); rtc_dev = kzalloc(sizeof(struct sunxi_rtc), GFP_KERNEL); if (!rtc_dev) return -ENOMEM; /* must before rtc_device_register, because it will call rtc_device_register -> __rtc_read_alarm -> * rtc_read_time-> __rtc_read_time -> sunxi_rtc_read_time, witch may use platform_get_drvdata. */ platform_set_drvdata(pdev, rtc_dev); rtc_dev->ac100 = dev_get_drvdata(pdev->dev.parent); #ifdef ENABLE_ALARM INIT_WORK(&rtc_dev->work, alarm_irq_work); device_init_wakeup(&pdev->dev, true); /* enable alarm wakeup */ #endif mutex_init(&rtc_dev->mutex); sunxi_rtc_hw_init(rtc_dev); #ifdef CONFIG_ARCH_SUN8IW6P1 /* * restore alarm interrupt enable which is cleared by u-boot, * rtc_device_register() need alarm interrupt enable bit to initialize alarm * */ reg_val = rtc_read_reg(rtc_dev->ac100, RTC_GP_REG_N_OFF); if (reg_val & 0x1) { rtc_write_reg(rtc_dev->ac100, ALM_INT_ENA_OFF, 1); } #endif rtc_dev->rtc = rtc_device_register(RTC_NAME, &pdev->dev, &sunxi_rtc_ops, THIS_MODULE); if (IS_ERR(rtc_dev->rtc)) { err = PTR_ERR(rtc_dev->rtc); kfree(rtc_dev); return err; } #ifdef ENABLE_ALARM sunxi_alarm_disable(rtc_dev); pr_info("%s(%d)!\n", __func__, __LINE__); err = arisc_nmi_cb_register(NMI_INT_TYPE_RTC, sunxi_irq_handle, (void *)rtc_dev); if (IS_ERR_VALUE(err)) { pr_err("%s(%d): request irq failed\n", __func__, __LINE__); rtc_device_unregister(rtc_dev->rtc); kfree(rtc_dev); return err; } #endif return 0; }
static void hibernate_restart(void) { uint32_t rtc_rtcsr,rtc_rtccr; while(!(rtc_read_reg(RTC_RTCCR) & RTCCR_WRDY)); rtc_rtcsr = rtc_read_reg(RTC_RTCSR); rtc_rtccr = rtc_read_reg(RTC_RTCCR); rtc_write_reg(RTC_RTCSAR,rtc_rtcsr + 5); rtc_rtccr &= ~(1 << 4); rtc_write_reg(RTC_RTCCR,rtc_rtccr | 0x3<<2); /* Clear reset status */ cpm_outl(0,CPM_RSR); /* Set minimum wakeup_n pin low-level assertion time for wakeup: 1000ms */ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(1000)); /* Set reset pin low-level assertion time after wakeup: must > 60ms */ rtc_write_reg(RTC_HRCR, (125 << 5)); /* clear wakeup status register */ rtc_write_reg(RTC_HWRSR, 0x0); rtc_write_reg(RTC_HWCR, 0x9); /* Put CPU to hibernate mode */ rtc_write_reg(RTC_HCR, 0x1); mdelay(200); while(1) printk("We should NOT come here.%08x\n",rtc_read_reg(RTC_HCR)); }
void rtc_write_count(uint32_t count) { union { uint8_t b[4]; uint32_t l; } mix; // write the counter shadow mix.l = count; rtc_write_reg(RTC_CAPTURE0, mix.b[0]); rtc_write_reg(RTC_CAPTURE1, mix.b[1]); rtc_write_reg(RTC_CAPTURE2, mix.b[2]); rtc_write_reg(RTC_CAPTURE3, mix.b[3]); // load the new value into the counter rtc_write_reg(RTC_CN, CN_LOAD); }
void alarm_enable(struct sunxi_rtc *rtc_dev) { #ifdef CONFIG_ARCH_SUN8IW6P1 int reg_val = 0; #endif /* enable alarm irq */ rtc_write_reg(rtc_dev->ac100, ALM_INT_ENA_OFF, 1); #ifdef CONFIG_ARCH_SUN8IW6P1 /* * shutdown alarm need alarm interrupt enable info when system startup, but * the info be cleared in u-boot boot process for a problem. so store the * info to RTC_GP_REG_N_OFF reg. * */ reg_val = rtc_read_reg(rtc_dev->ac100, RTC_GP_REG_N_OFF); reg_val |= 0x1; rtc_write_reg(rtc_dev->ac100, RTC_GP_REG_N_OFF, reg_val); #endif }
/// return the timer as a 8 bit value. /// /// @return The RTC clock in 25usec units /// uint8_t rtc_read_low(void) { // capture the current counter value rtc_write_reg(RTC_CN, CN_CAPTURE); // wait for capture to complete while (rtc_read_reg(RTC_CN) & RTC_CN_CAP) ; // read the counter shadow return rtc_read_reg(RTC_CAPTURE0); }
void jz_restart(char *command) { #if 1 printk("Restarting after 4ms\n"); REG_WDT_WCSR = WCSR_PRESCALE4 | WCSR_CLKIN_EXT; REG_WDT_WCNT = 0; REG_WDT_WDR = JZ_EXTAL / 1000; /* reset after 4ms */ REG_TCU_TSCR = TSCR_WDT; /* enable wdt clock */ REG_WDT_WCER = WCER_TCEN; /* wdt start */ #else printk("Restarting after 1s\n"); /* clear wakeup status register */ rtc_write_reg(RTC_HWRSR, 0x0); /* Scratch pad register to be reserved */ rtc_write_reg(RTC_HSPR, HSPR_RTCV); /* RTC Alarm Wakeup Enable */ rtc_set_reg(RTC_HWCR, HWCR_EALM); /* Set reset pin low-level assertion time after wakeup: must > 60ms */ rtc_write_reg(RTC_HRCR, HRCR_WAIT_TIME(60)); /* Set minimum wakeup_n pin low-level assertion time for wakeup: 100ms */ rtc_write_reg(RTC_HWFCR, HWFCR_WAIT_TIME(100)); rtc_write_reg(RTC_RTCSAR, rtc_read_reg(RTC_RTCSR) + 1); rtc_set_reg(RTC_RTCCR, RTCCR_AIE | RTCCR_AE | RTCCR_RTCE); /* alarm enable, alarm interrupt enable */ /* Put CPU to hibernate mode */ rtc_write_reg(RTC_HCR, HCR_PD); #endif while (1); }
/// return the timer as a 32 bit value. /// /// @return The RTC clock in 25usec units /// uint32_t rtc_read_count(void) { union { uint8_t b[4]; uint32_t l; } mix; // start a capture rtc_write_reg(RTC_CN, CN_CAPTURE); // wait for capture to complete while (rtc_read_reg(RTC_CN) & RTC_CN_CAP) ; // capture the current counter value registers // using a auto-incrementing strobe read RTC0ADR = RTC0ADR_BUSY | RTC0ADR_AUTO | RTC0ADR_SHORT; __asm NOP NOP NOP __endasm; mix.b[0] = RTC0DAT; __asm NOP NOP NOP __endasm; mix.b[1] = RTC0DAT; __asm NOP NOP NOP __endasm; mix.b[2] = RTC0DAT; __asm NOP NOP NOP __endasm; mix.b[3] = RTC0DAT; return mix.l; }
/* * Function: Keep power for CPU core when reset. * So that EPC, tcsm and so on can maintain it's status after reset-key pressed. */ void inline reset_keep_power(int keep_pwr) { if (keep_pwr) rtc_write_reg(RTC_PWRONCR, inl(RTC_IOBASE + RTC_PWRONCR) & ~(1 << 0)); }