summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMichael Brandt <michael.brandt@stericsson.com>2010-10-11 10:47:37 +0200
committerMichael BRANDT <michael.brandt@stericsson.com>2010-11-04 12:49:15 +0100
commit1e1e6a23e2a79cc2a282bf39090538889f1578c9 (patch)
tree86e98f78598c361c71d71339bdb53e4c94835d8c /drivers
parent14129f63eabe353023eccc443e36f7229d73cd71 (diff)
Add RTC driver for ST variant of pl031
The RTC implemented on the dbx500 SoCs is a derivative of the pl031. This driver supports the STv2 date/time layout. It is based on Linux drivers/rtc/rtc-pl031.c Change-Id: Iebe5973ba0627670f138631664748386b60f2b11 Signed-off-by: Michael Brandt <michael.brandt@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/6331 Reviewed-by: Carl-Johan IREKVIST <carl-johan.irekvist@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/7718 Reviewed-by: Mian Yousaf KAUKAB <mian.yousaf.kaukab@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/pl031_st.c212
2 files changed, 213 insertions, 0 deletions
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 772a49a90..4ae47c75e 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -56,6 +56,7 @@ COBJS-$(CONFIG_RTC_MPC5200) += mpc5xxx.o
COBJS-$(CONFIG_RTC_MPC8xx) += mpc8xx.o
COBJS-$(CONFIG_RTC_PCF8563) += pcf8563.o
COBJS-$(CONFIG_RTC_PL031) += pl031.o
+COBJS-$(CONFIG_RTC_PL031_ST) += pl031_st.o
COBJS-$(CONFIG_RTC_RS5C372A) += rs5c372.o
COBJS-$(CONFIG_RTC_RTC4543) += rtc4543.o
COBJS-$(CONFIG_RTC_RX8025) += rx8025.o
diff --git a/drivers/rtc/pl031_st.c b/drivers/rtc/pl031_st.c
new file mode 100644
index 000000000..c1b163de3
--- /dev/null
+++ b/drivers/rtc/pl031_st.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * based on Linux drivers/rtc/rtc-pl031.c:
+ *
+ * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
+ *
+ * Author: Deepak Saxena <dsaxena@plexity.net>
+ *
+ * Copyright 2006 (c) MontaVista Software, Inc.
+ *
+ * Author: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
+ * Copyright 2010 (c) ST-Ericsson AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <rtc.h>
+
+#if defined(CONFIG_CMD_DATE)
+
+#ifndef CONFIG_SYS_RTC_PL031_BASE
+#error CONFIG_SYS_RTC_PL031_BASE is not defined!
+#endif
+
+/*
+ * Register definitions
+ */
+#define RTC_DR 0x00 /* Data read register */
+#define RTC_MR 0x04 /* Match register */
+#define RTC_LR 0x08 /* Data load register */
+#define RTC_CR 0x0c /* Control register */
+#define RTC_IMSC 0x10 /* Interrupt mask and set register */
+#define RTC_RIS 0x14 /* Raw interrupt status register */
+#define RTC_MIS 0x18 /* Masked interrupt status register */
+#define RTC_ICR 0x1c /* Interrupt clear register */
+/* ST variants have additional timer functionality */
+#define RTC_TDR 0x20 /* Timer data read register */
+#define RTC_TLR 0x24 /* Timer data load register */
+#define RTC_TCR 0x28 /* Timer control register */
+#define RTC_YDR 0x30 /* Year data read register */
+#define RTC_YMR 0x34 /* Year match register */
+#define RTC_YLR 0x38 /* Year data load register */
+
+#define RTC_CR_CWEN (1 << 26) /* Clockwatch enable bit */
+
+/* Common bit definations for ST v2 for reading/writing time */
+#define RTC_SEC_SHIFT 0
+#define RTC_SEC_MASK (0x3F << RTC_SEC_SHIFT) /* Second [0-59] */
+#define RTC_MIN_SHIFT 6
+#define RTC_MIN_MASK (0x3F << RTC_MIN_SHIFT) /* Minute [0-59] */
+#define RTC_HOUR_SHIFT 12
+#define RTC_HOUR_MASK (0x1F << RTC_HOUR_SHIFT) /* Hour [0-23] */
+#define RTC_WDAY_SHIFT 17
+#define RTC_WDAY_MASK (0x7 << RTC_WDAY_SHIFT) /* Day of Week [1-7] 1=Sunday */
+#define RTC_MDAY_SHIFT 20
+#define RTC_MDAY_MASK (0x1F << RTC_MDAY_SHIFT) /* Day of Month [1-31] */
+#define RTC_MON_SHIFT 25
+#define RTC_MON_MASK (0xF << RTC_MON_SHIFT) /* Month [1-12] 1=January */
+
+static int pl031_initted = 0;
+
+/*
+ * Convert Gregorian date to ST v2 RTC format.
+ */
+static int pl031_stv2_tm_to_time(struct rtc_time *tm, unsigned long *st_time,
+ unsigned long *bcd_year)
+{
+ int year = tm->tm_year;
+ int wday = tm->tm_wday;
+
+ /* wday masking is not working in hardware so wday must be valid */
+ if (wday < -1 || wday > 6) {
+ printf("invalid wday value %d\n", tm->tm_wday);
+ return -1;
+ } else if (wday == -1) {
+ /* wday is not provided, calculate it here */
+ GregorianDay(tm);
+ wday = tm->tm_wday;
+ }
+
+ *bcd_year = (bin2bcd(year % 100) | bin2bcd(year / 100) << 8);
+
+ *st_time = (tm->tm_mon << RTC_MON_SHIFT)
+ | (tm->tm_mday << RTC_MDAY_SHIFT)
+ | ((wday + 1) << RTC_WDAY_SHIFT)
+ | (tm->tm_hour << RTC_HOUR_SHIFT)
+ | (tm->tm_min << RTC_MIN_SHIFT)
+ | (tm->tm_sec << RTC_SEC_SHIFT);
+
+ return 0;
+}
+
+/*
+ * Convert ST v2 RTC format to Gregorian date.
+ */
+static int pl031_stv2_time_to_tm(unsigned long st_time, unsigned long bcd_year,
+ struct rtc_time *tm)
+{
+ tm->tm_year = bcd2bin(bcd_year) + (bcd2bin(bcd_year >> 8) * 100);
+ tm->tm_mon = ((st_time & RTC_MON_MASK) >> RTC_MON_SHIFT);
+ tm->tm_mday = ((st_time & RTC_MDAY_MASK) >> RTC_MDAY_SHIFT);
+ tm->tm_wday = ((st_time & RTC_WDAY_MASK) >> RTC_WDAY_SHIFT) - 1;
+ tm->tm_hour = ((st_time & RTC_HOUR_MASK) >> RTC_HOUR_SHIFT);
+ tm->tm_min = ((st_time & RTC_MIN_MASK) >> RTC_MIN_SHIFT);
+ tm->tm_sec = ((st_time & RTC_SEC_MASK) >> RTC_SEC_SHIFT);
+
+ return 0;
+}
+
+static int pl031_stv2_read_time(struct rtc_time *tm)
+{
+
+ pl031_stv2_time_to_tm(readl(CONFIG_SYS_RTC_PL031_BASE + RTC_DR),
+ readl(CONFIG_SYS_RTC_PL031_BASE + RTC_YDR), tm);
+
+ return 0;
+}
+
+static int pl031_stv2_set_time(struct rtc_time *tm)
+{
+ unsigned long time;
+ unsigned long bcd_year;
+ int ret;
+
+ ret = pl031_stv2_tm_to_time(tm, &time, &bcd_year);
+ if (ret == 0) {
+ writel(bcd_year, CONFIG_SYS_RTC_PL031_BASE + RTC_YLR);
+ writel(time, CONFIG_SYS_RTC_PL031_BASE + RTC_LR);
+ }
+ /*
+ * The new setting is transferred to the ClockWatch counters on the
+ * next CLK1HZ rising edge after RTC_CWDLR register has been written.
+ */
+ udelay(1000 * 1000);
+
+ return ret;
+}
+
+/* Enable RTC Start in Control register*/
+void rtc_init(void)
+{
+ writel(readl(CONFIG_SYS_RTC_PL031_BASE + RTC_CR) | RTC_CR_CWEN,
+ CONFIG_SYS_RTC_PL031_BASE + RTC_CR);
+
+ pl031_initted = 1;
+}
+
+/*
+ * Reset the RTC. We set the date back to 1970-01-01.
+ */
+void rtc_reset(void)
+{
+ if (!pl031_initted)
+ rtc_init();
+ /* POR value, 2000-01-01 Sun */
+ writel(0x02120000, CONFIG_SYS_RTC_PL031_BASE + RTC_LR);
+ writel(0x2000, CONFIG_SYS_RTC_PL031_BASE + RTC_YLR);
+ /*
+ * The new setting is transferred to the ClockWatch counters on the
+ * next CLK1HZ rising edge after RTC_CWDLR register has been written.
+ */
+ udelay(1000 * 1000);
+}
+
+/*
+ * Set the RTC
+ */
+int rtc_set(struct rtc_time *tm)
+{
+
+ if (!pl031_initted)
+ rtc_init();
+
+ if (tm == NULL) {
+ puts("Error setting the date/time\n");
+ return -1;
+ }
+
+ return pl031_stv2_set_time(tm);
+}
+
+
+/*
+ * Get the current time from the RTC
+ */
+int rtc_get(struct rtc_time *tm)
+{
+
+ if (!pl031_initted)
+ rtc_init();
+
+ if (tm == NULL) {
+ puts("Error getting the date/time\n");
+ return -1;
+ }
+
+ pl031_stv2_read_time(tm);
+
+ debug("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+#endif