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 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 }
/// 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 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(); }
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; }
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 rtc_gettime(struct sunxi_rtc *rtc_dev, struct rtc_time *tm) { struct rtc_time time_tmp; int tmp; /* get sec */ tmp = rtc_read_reg(rtc_dev->ac100, RTC_SEC_REG_OFF); time_tmp.tm_sec = bcd2bin(tmp & 0x7f); /* get min */ tmp = rtc_read_reg(rtc_dev->ac100, RTC_MIN_REG_OFF); time_tmp.tm_min = bcd2bin(tmp & 0x7f); /* get hour */ tmp = rtc_read_reg(rtc_dev->ac100, RTC_HOU_REG_OFF); time_tmp.tm_hour = bcd2bin(tmp & 0x3f); /* get week day */ tmp = rtc_read_reg(rtc_dev->ac100, RTC_WEE_REG_OFF); time_tmp.tm_wday = bcd2bin(tmp & 0x7); /* get day */ tmp = rtc_read_reg(rtc_dev->ac100, RTC_DAY_REG_OFF); time_tmp.tm_mday = bcd2bin(tmp & 0x3f); /* get month */ tmp = rtc_read_reg(rtc_dev->ac100, RTC_MON_REG_OFF); time_tmp.tm_mon = bcd2bin(tmp & 0x1f); time_tmp.tm_mon -= 1; /* month is 1..12 in RTC reg but 0..11 in linux */ /* get year */ tmp = rtc_read_reg(rtc_dev->ac100, RTC_YEA_REG_OFF); tmp = bcd2bin(tmp & 0xff); time_tmp.tm_year = reg_year_to_actual_year(tmp) - 1900; /* in linux, tm_year=0 is 1900 */ pr_info("%s(%d): read time %d-%d-%d %d:%d:%d\n", __func__, __LINE__, time_tmp.tm_year + 1900, time_tmp.tm_mon + 1, time_tmp.tm_mday, time_tmp.tm_hour, time_tmp.tm_min, time_tmp.tm_sec); /* check if time read from rtc reg is OK */ if (!time_valid(&time_tmp)) { pr_err("%s(%d) err: retrieved date/time is not valid.\n", __func__, __LINE__); return -EIO; } *tm = time_tmp; return 0; }
/// 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; }
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 }
static int alarm_gettime(struct sunxi_rtc *rtc_dev, struct rtc_time *tm) { int reg_val; /* get sec */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_SEC_REG_OFF); tm->tm_sec = bcd2bin(reg_val & 0x7f); /* get minute */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_MIN_REG_OFF); tm->tm_min = bcd2bin(reg_val & 0x7f); /* get hour */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_HOU_REG_OFF); tm->tm_hour = bcd2bin(reg_val & 0x3f); /* get week */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_WEEK_REG_OFF); tm->tm_wday = bcd2bin(reg_val & 0x7); /* get day */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_DAY_REG_OFF); tm->tm_mday = bcd2bin(reg_val & 0x3f); /* get month */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_MON_REG_OFF); reg_val = bcd2bin(reg_val & 0x1f); tm->tm_mon = reg_val - 1; /* month is 1..12 in RTC reg but 0..11 in linux */ /* get year */ reg_val = rtc_read_reg(rtc_dev->ac100, ALM_YEA_REG_OFF); reg_val = bcd2bin(reg_val & 0xff); tm->tm_year = reg_year_to_actual_year(reg_val) - 1900; /* tm_year is from 1900 in linux */ pr_info("%s(%d): get alarm time %d-%d-%d %d:%d:%d success!\n", __func__, __LINE__, tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); /* check if time read from rtc reg is OK */ if (!time_valid(tm)) { pr_err("%s(%d) err: get time is not valid.\n", __func__, __LINE__); return -EIO; } return 0; }
static int sunxi_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) { struct platform_device *pdev = to_platform_device(dev); struct sunxi_rtc *rtc_dev = platform_get_drvdata(pdev); int ret = 0; int reg_val = 0; mutex_lock(&rtc_dev->mutex); /* get alarm time */ if (alarm_gettime(rtc_dev, &alrm->time)) { pr_err("%s(%d) err: get alarm time failed!\n", __func__, __LINE__); ret = -EINVAL; goto end; } reg_val = rtc_read_reg(rtc_dev->ac100, ALM_INT_ENA_OFF); if (reg_val & 0x1) alrm->enabled = 1; end: mutex_unlock(&rtc_dev->mutex); return ret; }
/* * Reads the date and time from the RTC. This is kind of slow. */ static void rtc_read(void) { uint8_t century = 0; uint8_t last_second; uint8_t last_minute; uint8_t last_hour; uint8_t last_day; uint8_t last_month; uint8_t last_year; uint8_t last_century; uint8_t registerB; while (rtc_update_in_progress()); time.second = rtc_read_reg(0x00); time.minute = rtc_read_reg(0x02); time.hour = rtc_read_reg(0x04); time.day = rtc_read_reg(0x07); time.month = rtc_read_reg(0x08); time.year = rtc_read_reg(0x09); // Read century century = rtc_read_reg(0x32); // Repeat the RTC read process until the values are consistent do { last_second = time.second; last_minute = time.minute; last_hour = time.hour; last_day = time.day; last_month = time.month; last_year = time.year; last_century = century; // Wait for there to not be an update while(rtc_update_in_progress()); time.second = rtc_read_reg(0x00); time.minute = rtc_read_reg(0x02); time.hour = rtc_read_reg(0x04); time.day = rtc_read_reg(0x07); time.month = rtc_read_reg(0x08); time.year = rtc_read_reg(0x09); century = rtc_read_reg(0x32); } while((last_second != time.second) || (last_minute != time.minute) || (last_hour != time.hour) || (last_day != time.day) || (last_month != time.month) || (last_year != time.year) || (last_century != century)); // Read register B (determine if 24 hour time) registerB = rtc_read_reg(0x0B); // Convert BCD to binary values if necessary if (!(registerB & 0x04)) { time.second = (time.second & 0x0F) + ((time.second / 16) * 10); time.minute = (time.minute & 0x0F) + ((time.minute / 16) * 10); time.hour = ((time.hour & 0x0F) + (((time.hour & 0x70) / 16) * 10) ) | (time.hour & 0x80); time.day = (time.day & 0x0F) + ((time.day / 16) * 10); time.month = (time.month & 0x0F) + ((time.month / 16) * 10); time.year = (time.year & 0x0F) + ((time.year / 16) * 10); century = (century & 0x0F) + ((century / 16) * 10); } // Convert 12 hour clock to 24 hour clock if necessary if (!(registerB & 0x02) && (time.hour & 0x80)) { time.hour = ((time.hour & 0x7F) + 12) % 24; } // Calculate the full (4-digit) year time.year += century * 100; }