common: Drop linux/delay.h from common header
[oweals/u-boot.git] / drivers / rtc / imxdi.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2009-2012 ADVANSEE
4  * Benoît Thébaudeau <benoit.thebaudeau@advansee.com>
5  *
6  * Based on the Linux rtc-imxdi.c driver, which is:
7  * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
8  * Copyright 2010 Orex Computed Radiography
9  */
10
11 /*
12  * Date & Time support for Freescale i.MX DryIce RTC
13  */
14
15 #include <common.h>
16 #include <command.h>
17 #include <linux/compat.h>
18 #include <rtc.h>
19 #include <linux/delay.h>
20
21 #include <asm/io.h>
22 #include <asm/arch/imx-regs.h>
23
24 /* DryIce Register Definitions */
25
26 struct imxdi_regs {
27         u32 dtcmr;                      /* Time Counter MSB Reg */
28         u32 dtclr;                      /* Time Counter LSB Reg */
29         u32 dcamr;                      /* Clock Alarm MSB Reg */
30         u32 dcalr;                      /* Clock Alarm LSB Reg */
31         u32 dcr;                        /* Control Reg */
32         u32 dsr;                        /* Status Reg */
33         u32 dier;                       /* Interrupt Enable Reg */
34 };
35
36 #define DCAMR_UNSET     0xFFFFFFFF      /* doomsday - 1 sec */
37
38 #define DCR_TCE         (1 << 3)        /* Time Counter Enable */
39
40 #define DSR_WBF         (1 << 10)       /* Write Busy Flag */
41 #define DSR_WNF         (1 << 9)        /* Write Next Flag */
42 #define DSR_WCF         (1 << 8)        /* Write Complete Flag */
43 #define DSR_WEF         (1 << 7)        /* Write Error Flag */
44 #define DSR_CAF         (1 << 4)        /* Clock Alarm Flag */
45 #define DSR_NVF         (1 << 1)        /* Non-Valid Flag */
46 #define DSR_SVF         (1 << 0)        /* Security Violation Flag */
47
48 #define DIER_WNIE       (1 << 9)        /* Write Next Interrupt Enable */
49 #define DIER_WCIE       (1 << 8)        /* Write Complete Interrupt Enable */
50 #define DIER_WEIE       (1 << 7)        /* Write Error Interrupt Enable */
51 #define DIER_CAIE       (1 << 4)        /* Clock Alarm Interrupt Enable */
52
53 /* Driver Private Data */
54
55 struct imxdi_data {
56         struct imxdi_regs __iomem       *regs;
57         int                             init_done;
58 };
59
60 static struct imxdi_data data;
61
62 /*
63  * This function attempts to clear the dryice write-error flag.
64  *
65  * A dryice write error is similar to a bus fault and should not occur in
66  * normal operation.  Clearing the flag requires another write, so the root
67  * cause of the problem may need to be fixed before the flag can be cleared.
68  */
69 static void clear_write_error(void)
70 {
71         int cnt;
72
73         puts("### Warning: RTC - Register write error!\n");
74
75         /* clear the write error flag */
76         __raw_writel(DSR_WEF, &data.regs->dsr);
77
78         /* wait for it to take effect */
79         for (cnt = 0; cnt < 1000; cnt++) {
80                 if ((__raw_readl(&data.regs->dsr) & DSR_WEF) == 0)
81                         return;
82                 udelay(10);
83         }
84         puts("### Error: RTC - Cannot clear write-error flag!\n");
85 }
86
87 /*
88  * Write a dryice register and wait until it completes.
89  *
90  * Use interrupt flags to determine when the write has completed.
91  */
92 #define DI_WRITE_WAIT(val, reg)                                         \
93 (                                                                       \
94         /* do the register write */                                     \
95         __raw_writel((val), &data.regs->reg),                           \
96                                                                         \
97         di_write_wait((val), #reg)                                      \
98 )
99 static int di_write_wait(u32 val, const char *reg)
100 {
101         int cnt;
102         int ret = 0;
103         int rc = 0;
104
105         /* wait for the write to finish */
106         for (cnt = 0; cnt < 100; cnt++) {
107                 if ((__raw_readl(&data.regs->dsr) & (DSR_WCF | DSR_WEF)) != 0) {
108                         ret = 1;
109                         break;
110                 }
111                 udelay(10);
112         }
113         if (ret == 0)
114                 printf("### Warning: RTC - Write-wait timeout "
115                                 "val = 0x%.8x reg = %s\n", val, reg);
116
117         /* check for write error */
118         if (__raw_readl(&data.regs->dsr) & DSR_WEF) {
119                 clear_write_error();
120                 rc = -1;
121         }
122
123         return rc;
124 }
125
126 /*
127  * Initialize dryice hardware
128  */
129 static int di_init(void)
130 {
131         int rc = 0;
132
133         data.regs = (struct imxdi_regs __iomem *)IMX_DRYICE_BASE;
134
135         /* mask all interrupts */
136         __raw_writel(0, &data.regs->dier);
137
138         /* put dryice into valid state */
139         if (__raw_readl(&data.regs->dsr) & DSR_NVF) {
140                 rc = DI_WRITE_WAIT(DSR_NVF | DSR_SVF, dsr);
141                 if (rc)
142                         goto err;
143         }
144
145         /* initialize alarm */
146         rc = DI_WRITE_WAIT(DCAMR_UNSET, dcamr);
147         if (rc)
148                 goto err;
149         rc = DI_WRITE_WAIT(0, dcalr);
150         if (rc)
151                 goto err;
152
153         /* clear alarm flag */
154         if (__raw_readl(&data.regs->dsr) & DSR_CAF) {
155                 rc = DI_WRITE_WAIT(DSR_CAF, dsr);
156                 if (rc)
157                         goto err;
158         }
159
160         /* the timer won't count if it has never been written to */
161         if (__raw_readl(&data.regs->dtcmr) == 0) {
162                 rc = DI_WRITE_WAIT(0, dtcmr);
163                 if (rc)
164                         goto err;
165         }
166
167         /* start keeping time */
168         if (!(__raw_readl(&data.regs->dcr) & DCR_TCE)) {
169                 rc = DI_WRITE_WAIT(__raw_readl(&data.regs->dcr) | DCR_TCE, dcr);
170                 if (rc)
171                         goto err;
172         }
173
174         data.init_done = 1;
175         return 0;
176
177 err:
178         return rc;
179 }
180
181 int rtc_get(struct rtc_time *tmp)
182 {
183         unsigned long now;
184         int rc = 0;
185
186         if (!data.init_done) {
187                 rc = di_init();
188                 if (rc)
189                         goto err;
190         }
191
192         now = __raw_readl(&data.regs->dtcmr);
193         rtc_to_tm(now, tmp);
194
195 err:
196         return rc;
197 }
198
199 int rtc_set(struct rtc_time *tmp)
200 {
201         unsigned long now;
202         int rc;
203
204         if (!data.init_done) {
205                 rc = di_init();
206                 if (rc)
207                         goto err;
208         }
209
210         now = rtc_mktime(tmp);
211         /* zero the fractional part first */
212         rc = DI_WRITE_WAIT(0, dtclr);
213         if (rc == 0)
214                 rc = DI_WRITE_WAIT(now, dtcmr);
215
216 err:
217         return rc;
218 }
219
220 void rtc_reset(void)
221 {
222         di_init();
223 }