Beispiel #1
0
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
}
Beispiel #3
0
/// 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);
}
Beispiel #4
0
/// 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;
}
Beispiel #10
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));

}
Beispiel #11
0
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
}
Beispiel #13
0
/// 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);
}
Beispiel #14
0
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);
}
Beispiel #15
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;
}
Beispiel #16
0
/*
 * 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));
}