2 * (C) Copyright 2009-2012 ADVANSEE
3 * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
5 * Based on the Linux rtc-imxdi.c driver, which is:
6 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2010 Orex Computed Radiography
9 * See file CREDITS for list of people who contributed to this
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation; either version 2 of
15 * the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
29 * Date & Time support for Freescale i.MX DryIce RTC
34 #include <linux/compat.h>
37 #if defined(CONFIG_CMD_DATE)
40 #include <asm/arch/imx-regs.h>
42 /* DryIce Register Definitions */
45 u32 dtcmr; /* Time Counter MSB Reg */
46 u32 dtclr; /* Time Counter LSB Reg */
47 u32 dcamr; /* Clock Alarm MSB Reg */
48 u32 dcalr; /* Clock Alarm LSB Reg */
49 u32 dcr; /* Control Reg */
50 u32 dsr; /* Status Reg */
51 u32 dier; /* Interrupt Enable Reg */
54 #define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */
56 #define DCR_TCE (1 << 3) /* Time Counter Enable */
58 #define DSR_WBF (1 << 10) /* Write Busy Flag */
59 #define DSR_WNF (1 << 9) /* Write Next Flag */
60 #define DSR_WCF (1 << 8) /* Write Complete Flag */
61 #define DSR_WEF (1 << 7) /* Write Error Flag */
62 #define DSR_CAF (1 << 4) /* Clock Alarm Flag */
63 #define DSR_NVF (1 << 1) /* Non-Valid Flag */
64 #define DSR_SVF (1 << 0) /* Security Violation Flag */
66 #define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */
67 #define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */
68 #define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */
69 #define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */
71 /* Driver Private Data */
74 struct imxdi_regs __iomem *regs;
78 static struct imxdi_data data;
81 * This function attempts to clear the dryice write-error flag.
83 * A dryice write error is similar to a bus fault and should not occur in
84 * normal operation. Clearing the flag requires another write, so the root
85 * cause of the problem may need to be fixed before the flag can be cleared.
87 static void clear_write_error(void)
91 puts("### Warning: RTC - Register write error!\n");
93 /* clear the write error flag */
94 __raw_writel(DSR_WEF, &data.regs->dsr);
96 /* wait for it to take effect */
97 for (cnt = 0; cnt < 1000; cnt++) {
98 if ((__raw_readl(&data.regs->dsr) & DSR_WEF) == 0)
102 puts("### Error: RTC - Cannot clear write-error flag!\n");
106 * Write a dryice register and wait until it completes.
108 * Use interrupt flags to determine when the write has completed.
110 #define DI_WRITE_WAIT(val, reg) \
112 /* do the register write */ \
113 __raw_writel((val), &data.regs->reg), \
115 di_write_wait((val), #reg) \
117 static int di_write_wait(u32 val, const char *reg)
123 /* wait for the write to finish */
124 for (cnt = 0; cnt < 100; cnt++) {
125 if ((__raw_readl(&data.regs->dsr) & (DSR_WCF | DSR_WEF)) != 0) {
132 printf("### Warning: RTC - Write-wait timeout "
133 "val = 0x%.8x reg = %s\n", val, reg);
135 /* check for write error */
136 if (__raw_readl(&data.regs->dsr) & DSR_WEF) {
145 * Initialize dryice hardware
147 static int di_init(void)
151 data.regs = (struct imxdi_regs __iomem *)IMX_DRYICE_BASE;
153 /* mask all interrupts */
154 __raw_writel(0, &data.regs->dier);
156 /* put dryice into valid state */
157 if (__raw_readl(&data.regs->dsr) & DSR_NVF) {
158 rc = DI_WRITE_WAIT(DSR_NVF | DSR_SVF, dsr);
163 /* initialize alarm */
164 rc = DI_WRITE_WAIT(DCAMR_UNSET, dcamr);
167 rc = DI_WRITE_WAIT(0, dcalr);
171 /* clear alarm flag */
172 if (__raw_readl(&data.regs->dsr) & DSR_CAF) {
173 rc = DI_WRITE_WAIT(DSR_CAF, dsr);
178 /* the timer won't count if it has never been written to */
179 if (__raw_readl(&data.regs->dtcmr) == 0) {
180 rc = DI_WRITE_WAIT(0, dtcmr);
185 /* start keeping time */
186 if (!(__raw_readl(&data.regs->dcr) & DCR_TCE)) {
187 rc = DI_WRITE_WAIT(__raw_readl(&data.regs->dcr) | DCR_TCE, dcr);
199 int rtc_get(struct rtc_time *tmp)
204 if (!data.init_done) {
210 now = __raw_readl(&data.regs->dtcmr);
217 int rtc_set(struct rtc_time *tmp)
222 if (!data.init_done) {
228 now = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
229 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
230 /* zero the fractional part first */
231 rc = DI_WRITE_WAIT(0, dtclr);
233 rc = DI_WRITE_WAIT(now, dtcmr);