blob: 63ca52b2029b757ba6e19f421d0b2473510fbb74 [file] [log] [blame]
Baruch Siacheba54542010-08-10 18:02:13 -07001/*
2 * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2010 Orex Computed Radiography
4 */
5
6/*
7 * The code contained herein is licensed under the GNU General Public
8 * License. You may obtain a copy of the GNU General Public License
9 * Version 2 or later at the following locations:
10 *
11 * http://www.opensource.org/licenses/gpl-license.html
12 * http://www.gnu.org/copyleft/gpl.html
13 */
14
15/* based on rtc-mc13892.c */
16
17/*
18 * This driver uses the 47-bit 32 kHz counter in the Freescale DryIce block
19 * to implement a Linux RTC. Times and alarms are truncated to seconds.
20 * Since the RTC framework performs API locking via rtc->ops_lock the
21 * only simultaneous accesses we need to deal with is updating DryIce
22 * registers while servicing an alarm.
23 *
24 * Note that reading the DSR (DryIce Status Register) automatically clears
25 * the WCF (Write Complete Flag). All DryIce writes are synchronized to the
26 * LP (Low Power) domain and set the WCF upon completion. Writes to the
27 * DIER (DryIce Interrupt Enable Register) are the only exception. These
28 * occur at normal bus speeds and do not set WCF. Periodic interrupts are
29 * not supported by the hardware.
30 */
31
32#include <linux/io.h>
33#include <linux/clk.h>
34#include <linux/delay.h>
35#include <linux/module.h>
36#include <linux/platform_device.h>
37#include <linux/rtc.h>
Axel Lind4c32f32011-09-14 16:21:47 -070038#include <linux/sched.h>
Jean Delvareba3f7a12012-12-20 15:05:19 -080039#include <linux/spinlock.h>
Baruch Siacheba54542010-08-10 18:02:13 -070040#include <linux/workqueue.h>
Roland Stigge968d21c2012-12-17 16:02:23 -080041#include <linux/of.h>
Baruch Siacheba54542010-08-10 18:02:13 -070042
43/* DryIce Register Definitions */
44
45#define DTCMR 0x00 /* Time Counter MSB Reg */
46#define DTCLR 0x04 /* Time Counter LSB Reg */
47
48#define DCAMR 0x08 /* Clock Alarm MSB Reg */
49#define DCALR 0x0c /* Clock Alarm LSB Reg */
50#define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */
51
52#define DCR 0x10 /* Control Reg */
Juergen Borleis46edeff2015-02-13 14:40:45 -080053#define DCR_TDCHL (1 << 30) /* Tamper-detect configuration hard lock */
54#define DCR_TDCSL (1 << 29) /* Tamper-detect configuration soft lock */
55#define DCR_KSSL (1 << 27) /* Key-select soft lock */
56#define DCR_MCHL (1 << 20) /* Monotonic-counter hard lock */
57#define DCR_MCSL (1 << 19) /* Monotonic-counter soft lock */
58#define DCR_TCHL (1 << 18) /* Timer-counter hard lock */
59#define DCR_TCSL (1 << 17) /* Timer-counter soft lock */
60#define DCR_FSHL (1 << 16) /* Failure state hard lock */
Baruch Siacheba54542010-08-10 18:02:13 -070061#define DCR_TCE (1 << 3) /* Time Counter Enable */
Juergen Borleis46edeff2015-02-13 14:40:45 -080062#define DCR_MCE (1 << 2) /* Monotonic Counter Enable */
Baruch Siacheba54542010-08-10 18:02:13 -070063
64#define DSR 0x14 /* Status Reg */
Juergen Borleis46edeff2015-02-13 14:40:45 -080065#define DSR_WTD (1 << 23) /* Wire-mesh tamper detected */
66#define DSR_ETBD (1 << 22) /* External tamper B detected */
67#define DSR_ETAD (1 << 21) /* External tamper A detected */
68#define DSR_EBD (1 << 20) /* External boot detected */
69#define DSR_SAD (1 << 19) /* SCC alarm detected */
70#define DSR_TTD (1 << 18) /* Temperatur tamper detected */
71#define DSR_CTD (1 << 17) /* Clock tamper detected */
72#define DSR_VTD (1 << 16) /* Voltage tamper detected */
73#define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */
74#define DSR_WNF (1 << 9) /* Write Next Flag (synchronous) */
75#define DSR_WCF (1 << 8) /* Write Complete Flag (synchronous)*/
Baruch Siacheba54542010-08-10 18:02:13 -070076#define DSR_WEF (1 << 7) /* Write Error Flag */
77#define DSR_CAF (1 << 4) /* Clock Alarm Flag */
Juergen Borleis46edeff2015-02-13 14:40:45 -080078#define DSR_MCO (1 << 3) /* monotonic counter overflow */
79#define DSR_TCO (1 << 2) /* time counter overflow */
Baruch Siacheba54542010-08-10 18:02:13 -070080#define DSR_NVF (1 << 1) /* Non-Valid Flag */
81#define DSR_SVF (1 << 0) /* Security Violation Flag */
82
Juergen Borleis46edeff2015-02-13 14:40:45 -080083#define DIER 0x18 /* Interrupt Enable Reg (synchronous) */
Baruch Siacheba54542010-08-10 18:02:13 -070084#define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */
85#define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */
86#define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */
87#define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */
Juergen Borleis46edeff2015-02-13 14:40:45 -080088#define DIER_SVIE (1 << 0) /* Security-violation Interrupt Enable */
89
90#define DMCR 0x1c /* DryIce Monotonic Counter Reg */
91
92#define DTCR 0x28 /* DryIce Tamper Configuration Reg */
93#define DTCR_MOE (1 << 9) /* monotonic overflow enabled */
94#define DTCR_TOE (1 << 8) /* time overflow enabled */
95#define DTCR_WTE (1 << 7) /* wire-mesh tamper enabled */
96#define DTCR_ETBE (1 << 6) /* external B tamper enabled */
97#define DTCR_ETAE (1 << 5) /* external A tamper enabled */
98#define DTCR_EBE (1 << 4) /* external boot tamper enabled */
99#define DTCR_SAIE (1 << 3) /* SCC enabled */
100#define DTCR_TTE (1 << 2) /* temperature tamper enabled */
101#define DTCR_CTE (1 << 1) /* clock tamper enabled */
102#define DTCR_VTE (1 << 0) /* voltage tamper enabled */
103
104#define DGPR 0x3c /* DryIce General Purpose Reg */
Baruch Siacheba54542010-08-10 18:02:13 -0700105
106/**
107 * struct imxdi_dev - private imxdi rtc data
108 * @pdev: pionter to platform dev
109 * @rtc: pointer to rtc struct
110 * @ioaddr: IO registers pointer
111 * @irq: dryice normal interrupt
112 * @clk: input reference clock
113 * @dsr: copy of the DSR register
114 * @irq_lock: interrupt enable register (DIER) lock
115 * @write_wait: registers write complete queue
116 * @write_mutex: serialize registers write
117 * @work: schedule alarm work
118 */
119struct imxdi_dev {
120 struct platform_device *pdev;
121 struct rtc_device *rtc;
122 void __iomem *ioaddr;
123 int irq;
124 struct clk *clk;
125 u32 dsr;
126 spinlock_t irq_lock;
127 wait_queue_head_t write_wait;
128 struct mutex write_mutex;
129 struct work_struct work;
130};
131
Juergen Borleis3ba3fab2015-04-27 15:59:48 +0200132/* Some background:
133 *
134 * The DryIce unit is a complex security/tamper monitor device. To be able do
135 * its job in a useful manner it runs a bigger statemachine to bring it into
136 * security/tamper failure state and once again to bring it out of this state.
137 *
138 * This unit can be in one of three states:
139 *
140 * - "NON-VALID STATE"
141 * always after the battery power was removed
142 * - "FAILURE STATE"
143 * if one of the enabled security events has happened
144 * - "VALID STATE"
145 * if the unit works as expected
146 *
147 * Everything stops when the unit enters the failure state including the RTC
148 * counter (to be able to detect the time the security event happened).
149 *
150 * The following events (when enabled) let the DryIce unit enter the failure
151 * state:
152 *
153 * - wire-mesh-tamper detect
154 * - external tamper B detect
155 * - external tamper A detect
156 * - temperature tamper detect
157 * - clock tamper detect
158 * - voltage tamper detect
159 * - RTC counter overflow
160 * - monotonic counter overflow
161 * - external boot
162 *
163 * If we find the DryIce unit in "FAILURE STATE" and the TDCHL cleared, we
164 * can only detect this state. In this case the unit is completely locked and
165 * must force a second "SYSTEM POR" to bring the DryIce into the
166 * "NON-VALID STATE" + "FAILURE STATE" where a recovery is possible.
167 * If the TDCHL is set in the "FAILURE STATE" we are out of luck. In this case
168 * a battery power cycle is required.
169 *
170 * In the "NON-VALID STATE" + "FAILURE STATE" we can clear the "FAILURE STATE"
171 * and recover the DryIce unit. By clearing the "NON-VALID STATE" as the last
172 * task, we bring back this unit into life.
173 */
174
Baruch Siacheba54542010-08-10 18:02:13 -0700175/*
176 * enable a dryice interrupt
177 */
178static void di_int_enable(struct imxdi_dev *imxdi, u32 intr)
179{
180 unsigned long flags;
181
182 spin_lock_irqsave(&imxdi->irq_lock, flags);
Juergen Borleise30d3132015-04-27 15:59:47 +0200183 writel(readl(imxdi->ioaddr + DIER) | intr,
184 imxdi->ioaddr + DIER);
Baruch Siacheba54542010-08-10 18:02:13 -0700185 spin_unlock_irqrestore(&imxdi->irq_lock, flags);
186}
187
188/*
189 * disable a dryice interrupt
190 */
191static void di_int_disable(struct imxdi_dev *imxdi, u32 intr)
192{
193 unsigned long flags;
194
195 spin_lock_irqsave(&imxdi->irq_lock, flags);
Juergen Borleise30d3132015-04-27 15:59:47 +0200196 writel(readl(imxdi->ioaddr + DIER) & ~intr,
197 imxdi->ioaddr + DIER);
Baruch Siacheba54542010-08-10 18:02:13 -0700198 spin_unlock_irqrestore(&imxdi->irq_lock, flags);
199}
200
201/*
202 * This function attempts to clear the dryice write-error flag.
203 *
204 * A dryice write error is similar to a bus fault and should not occur in
205 * normal operation. Clearing the flag requires another write, so the root
206 * cause of the problem may need to be fixed before the flag can be cleared.
207 */
208static void clear_write_error(struct imxdi_dev *imxdi)
209{
210 int cnt;
211
212 dev_warn(&imxdi->pdev->dev, "WARNING: Register write error!\n");
213
214 /* clear the write error flag */
Juergen Borleise30d3132015-04-27 15:59:47 +0200215 writel(DSR_WEF, imxdi->ioaddr + DSR);
Baruch Siacheba54542010-08-10 18:02:13 -0700216
217 /* wait for it to take effect */
218 for (cnt = 0; cnt < 1000; cnt++) {
Juergen Borleise30d3132015-04-27 15:59:47 +0200219 if ((readl(imxdi->ioaddr + DSR) & DSR_WEF) == 0)
Baruch Siacheba54542010-08-10 18:02:13 -0700220 return;
221 udelay(10);
222 }
223 dev_err(&imxdi->pdev->dev,
224 "ERROR: Cannot clear write-error flag!\n");
225}
226
227/*
228 * Write a dryice register and wait until it completes.
229 *
230 * This function uses interrupts to determine when the
231 * write has completed.
232 */
233static int di_write_wait(struct imxdi_dev *imxdi, u32 val, int reg)
234{
235 int ret;
236 int rc = 0;
237
238 /* serialize register writes */
239 mutex_lock(&imxdi->write_mutex);
240
241 /* enable the write-complete interrupt */
242 di_int_enable(imxdi, DIER_WCIE);
243
244 imxdi->dsr = 0;
245
246 /* do the register write */
Juergen Borleise30d3132015-04-27 15:59:47 +0200247 writel(val, imxdi->ioaddr + reg);
Baruch Siacheba54542010-08-10 18:02:13 -0700248
249 /* wait for the write to finish */
250 ret = wait_event_interruptible_timeout(imxdi->write_wait,
251 imxdi->dsr & (DSR_WCF | DSR_WEF), msecs_to_jiffies(1));
252 if (ret < 0) {
253 rc = ret;
254 goto out;
255 } else if (ret == 0) {
256 dev_warn(&imxdi->pdev->dev,
257 "Write-wait timeout "
258 "val = 0x%08x reg = 0x%08x\n", val, reg);
259 }
260
261 /* check for write error */
262 if (imxdi->dsr & DSR_WEF) {
263 clear_write_error(imxdi);
264 rc = -EIO;
265 }
266
267out:
268 mutex_unlock(&imxdi->write_mutex);
269
270 return rc;
271}
272
273/*
274 * read the seconds portion of the current time from the dryice time counter
275 */
276static int dryice_rtc_read_time(struct device *dev, struct rtc_time *tm)
277{
278 struct imxdi_dev *imxdi = dev_get_drvdata(dev);
279 unsigned long now;
280
Juergen Borleise30d3132015-04-27 15:59:47 +0200281 now = readl(imxdi->ioaddr + DTCMR);
Baruch Siacheba54542010-08-10 18:02:13 -0700282 rtc_time_to_tm(now, tm);
283
284 return 0;
285}
286
287/*
288 * set the seconds portion of dryice time counter and clear the
289 * fractional part.
290 */
291static int dryice_rtc_set_mmss(struct device *dev, unsigned long secs)
292{
293 struct imxdi_dev *imxdi = dev_get_drvdata(dev);
294 int rc;
295
296 /* zero the fractional part first */
297 rc = di_write_wait(imxdi, 0, DTCLR);
298 if (rc == 0)
299 rc = di_write_wait(imxdi, secs, DTCMR);
300
301 return rc;
302}
303
304static int dryice_rtc_alarm_irq_enable(struct device *dev,
305 unsigned int enabled)
306{
307 struct imxdi_dev *imxdi = dev_get_drvdata(dev);
308
309 if (enabled)
310 di_int_enable(imxdi, DIER_CAIE);
311 else
312 di_int_disable(imxdi, DIER_CAIE);
313
314 return 0;
315}
316
317/*
318 * read the seconds portion of the alarm register.
319 * the fractional part of the alarm register is always zero.
320 */
321static int dryice_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
322{
323 struct imxdi_dev *imxdi = dev_get_drvdata(dev);
324 u32 dcamr;
325
Juergen Borleise30d3132015-04-27 15:59:47 +0200326 dcamr = readl(imxdi->ioaddr + DCAMR);
Baruch Siacheba54542010-08-10 18:02:13 -0700327 rtc_time_to_tm(dcamr, &alarm->time);
328
329 /* alarm is enabled if the interrupt is enabled */
Juergen Borleise30d3132015-04-27 15:59:47 +0200330 alarm->enabled = (readl(imxdi->ioaddr + DIER) & DIER_CAIE) != 0;
Baruch Siacheba54542010-08-10 18:02:13 -0700331
332 /* don't allow the DSR read to mess up DSR_WCF */
333 mutex_lock(&imxdi->write_mutex);
334
335 /* alarm is pending if the alarm flag is set */
Juergen Borleise30d3132015-04-27 15:59:47 +0200336 alarm->pending = (readl(imxdi->ioaddr + DSR) & DSR_CAF) != 0;
Baruch Siacheba54542010-08-10 18:02:13 -0700337
338 mutex_unlock(&imxdi->write_mutex);
339
340 return 0;
341}
342
343/*
344 * set the seconds portion of dryice alarm register
345 */
346static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
347{
348 struct imxdi_dev *imxdi = dev_get_drvdata(dev);
349 unsigned long now;
350 unsigned long alarm_time;
351 int rc;
352
353 rc = rtc_tm_to_time(&alarm->time, &alarm_time);
354 if (rc)
355 return rc;
356
357 /* don't allow setting alarm in the past */
Juergen Borleise30d3132015-04-27 15:59:47 +0200358 now = readl(imxdi->ioaddr + DTCMR);
Baruch Siacheba54542010-08-10 18:02:13 -0700359 if (alarm_time < now)
360 return -EINVAL;
361
362 /* write the new alarm time */
363 rc = di_write_wait(imxdi, (u32)alarm_time, DCAMR);
364 if (rc)
365 return rc;
366
367 if (alarm->enabled)
368 di_int_enable(imxdi, DIER_CAIE); /* enable alarm intr */
369 else
370 di_int_disable(imxdi, DIER_CAIE); /* disable alarm intr */
371
372 return 0;
373}
374
375static struct rtc_class_ops dryice_rtc_ops = {
376 .read_time = dryice_rtc_read_time,
377 .set_mmss = dryice_rtc_set_mmss,
378 .alarm_irq_enable = dryice_rtc_alarm_irq_enable,
379 .read_alarm = dryice_rtc_read_alarm,
380 .set_alarm = dryice_rtc_set_alarm,
381};
382
383/*
384 * dryice "normal" interrupt handler
385 */
386static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
387{
388 struct imxdi_dev *imxdi = dev_id;
389 u32 dsr, dier;
390 irqreturn_t rc = IRQ_NONE;
391
Juergen Borleise30d3132015-04-27 15:59:47 +0200392 dier = readl(imxdi->ioaddr + DIER);
Baruch Siacheba54542010-08-10 18:02:13 -0700393
394 /* handle write complete and write error cases */
Juergen Borleis6df17a62015-02-13 14:40:42 -0800395 if (dier & DIER_WCIE) {
Baruch Siacheba54542010-08-10 18:02:13 -0700396 /*If the write wait queue is empty then there is no pending
397 operations. It means the interrupt is for DryIce -Security.
398 IRQ must be returned as none.*/
399 if (list_empty_careful(&imxdi->write_wait.task_list))
400 return rc;
401
402 /* DSR_WCF clears itself on DSR read */
Juergen Borleise30d3132015-04-27 15:59:47 +0200403 dsr = readl(imxdi->ioaddr + DSR);
Juergen Borleis6df17a62015-02-13 14:40:42 -0800404 if (dsr & (DSR_WCF | DSR_WEF)) {
Baruch Siacheba54542010-08-10 18:02:13 -0700405 /* mask the interrupt */
406 di_int_disable(imxdi, DIER_WCIE);
407
408 /* save the dsr value for the wait queue */
409 imxdi->dsr |= dsr;
410
411 wake_up_interruptible(&imxdi->write_wait);
412 rc = IRQ_HANDLED;
413 }
414 }
415
416 /* handle the alarm case */
Juergen Borleis6df17a62015-02-13 14:40:42 -0800417 if (dier & DIER_CAIE) {
Baruch Siacheba54542010-08-10 18:02:13 -0700418 /* DSR_WCF clears itself on DSR read */
Juergen Borleise30d3132015-04-27 15:59:47 +0200419 dsr = readl(imxdi->ioaddr + DSR);
Baruch Siacheba54542010-08-10 18:02:13 -0700420 if (dsr & DSR_CAF) {
421 /* mask the interrupt */
422 di_int_disable(imxdi, DIER_CAIE);
423
424 /* finish alarm in user context */
425 schedule_work(&imxdi->work);
426 rc = IRQ_HANDLED;
427 }
428 }
429 return rc;
430}
431
432/*
433 * post the alarm event from user context so it can sleep
434 * on the write completion.
435 */
436static void dryice_work(struct work_struct *work)
437{
438 struct imxdi_dev *imxdi = container_of(work,
439 struct imxdi_dev, work);
440
441 /* dismiss the interrupt (ignore error) */
442 di_write_wait(imxdi, DSR_CAF, DSR);
443
444 /* pass the alarm event to the rtc framework. */
445 rtc_update_irq(imxdi->rtc, 1, RTC_AF | RTC_IRQF);
446}
447
448/*
449 * probe for dryice rtc device
450 */
Jingoo Han5073cba2013-04-29 16:18:24 -0700451static int __init dryice_rtc_probe(struct platform_device *pdev)
Baruch Siacheba54542010-08-10 18:02:13 -0700452{
453 struct resource *res;
454 struct imxdi_dev *imxdi;
455 int rc;
456
Baruch Siacheba54542010-08-10 18:02:13 -0700457 imxdi = devm_kzalloc(&pdev->dev, sizeof(*imxdi), GFP_KERNEL);
458 if (!imxdi)
459 return -ENOMEM;
460
461 imxdi->pdev = pdev;
462
Julia Lawall7c1d69e2013-09-11 14:24:27 -0700463 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
464 imxdi->ioaddr = devm_ioremap_resource(&pdev->dev, res);
465 if (IS_ERR(imxdi->ioaddr))
466 return PTR_ERR(imxdi->ioaddr);
Baruch Siacheba54542010-08-10 18:02:13 -0700467
Jan Luebbefee0de72012-10-25 13:38:11 -0700468 spin_lock_init(&imxdi->irq_lock);
469
Baruch Siacheba54542010-08-10 18:02:13 -0700470 imxdi->irq = platform_get_irq(pdev, 0);
471 if (imxdi->irq < 0)
472 return imxdi->irq;
473
474 init_waitqueue_head(&imxdi->write_wait);
475
476 INIT_WORK(&imxdi->work, dryice_work);
477
478 mutex_init(&imxdi->write_mutex);
479
Jingoo Han95108532013-02-21 16:45:35 -0800480 imxdi->clk = devm_clk_get(&pdev->dev, NULL);
Baruch Siacheba54542010-08-10 18:02:13 -0700481 if (IS_ERR(imxdi->clk))
482 return PTR_ERR(imxdi->clk);
Fabio Estevam3378f732014-04-03 14:49:38 -0700483 rc = clk_prepare_enable(imxdi->clk);
484 if (rc)
485 return rc;
Baruch Siacheba54542010-08-10 18:02:13 -0700486
487 /*
488 * Initialize dryice hardware
489 */
490
491 /* mask all interrupts */
Juergen Borleise30d3132015-04-27 15:59:47 +0200492 writel(0, imxdi->ioaddr + DIER);
Baruch Siacheba54542010-08-10 18:02:13 -0700493
494 rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq,
495 IRQF_SHARED, pdev->name, imxdi);
496 if (rc) {
497 dev_warn(&pdev->dev, "interrupt not available.\n");
498 goto err;
499 }
500
501 /* put dryice into valid state */
Juergen Borleise30d3132015-04-27 15:59:47 +0200502 if (readl(imxdi->ioaddr + DSR) & DSR_NVF) {
Baruch Siacheba54542010-08-10 18:02:13 -0700503 rc = di_write_wait(imxdi, DSR_NVF | DSR_SVF, DSR);
504 if (rc)
505 goto err;
506 }
507
508 /* initialize alarm */
509 rc = di_write_wait(imxdi, DCAMR_UNSET, DCAMR);
510 if (rc)
511 goto err;
512 rc = di_write_wait(imxdi, 0, DCALR);
513 if (rc)
514 goto err;
515
516 /* clear alarm flag */
Juergen Borleise30d3132015-04-27 15:59:47 +0200517 if (readl(imxdi->ioaddr + DSR) & DSR_CAF) {
Baruch Siacheba54542010-08-10 18:02:13 -0700518 rc = di_write_wait(imxdi, DSR_CAF, DSR);
519 if (rc)
520 goto err;
521 }
522
523 /* the timer won't count if it has never been written to */
Juergen Borleise30d3132015-04-27 15:59:47 +0200524 if (readl(imxdi->ioaddr + DTCMR) == 0) {
Baruch Siacheba54542010-08-10 18:02:13 -0700525 rc = di_write_wait(imxdi, 0, DTCMR);
526 if (rc)
527 goto err;
528 }
529
530 /* start keeping time */
Juergen Borleise30d3132015-04-27 15:59:47 +0200531 if (!(readl(imxdi->ioaddr + DCR) & DCR_TCE)) {
Baruch Siacheba54542010-08-10 18:02:13 -0700532 rc = di_write_wait(imxdi,
Juergen Borleise30d3132015-04-27 15:59:47 +0200533 readl(imxdi->ioaddr + DCR) | DCR_TCE,
Baruch Siacheba54542010-08-10 18:02:13 -0700534 DCR);
535 if (rc)
536 goto err;
537 }
538
539 platform_set_drvdata(pdev, imxdi);
Jingoo Han04f70e42013-04-29 16:19:03 -0700540 imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
Baruch Siacheba54542010-08-10 18:02:13 -0700541 &dryice_rtc_ops, THIS_MODULE);
542 if (IS_ERR(imxdi->rtc)) {
543 rc = PTR_ERR(imxdi->rtc);
544 goto err;
545 }
546
547 return 0;
548
549err:
Sascha Hauer4ec8c7f2012-04-25 16:35:16 +0200550 clk_disable_unprepare(imxdi->clk);
Baruch Siacheba54542010-08-10 18:02:13 -0700551
552 return rc;
553}
554
Jingoo Han5073cba2013-04-29 16:18:24 -0700555static int __exit dryice_rtc_remove(struct platform_device *pdev)
Baruch Siacheba54542010-08-10 18:02:13 -0700556{
557 struct imxdi_dev *imxdi = platform_get_drvdata(pdev);
558
559 flush_work(&imxdi->work);
560
561 /* mask all interrupts */
Juergen Borleise30d3132015-04-27 15:59:47 +0200562 writel(0, imxdi->ioaddr + DIER);
Baruch Siacheba54542010-08-10 18:02:13 -0700563
Sascha Hauer4ec8c7f2012-04-25 16:35:16 +0200564 clk_disable_unprepare(imxdi->clk);
Baruch Siacheba54542010-08-10 18:02:13 -0700565
566 return 0;
567}
568
Roland Stigge968d21c2012-12-17 16:02:23 -0800569#ifdef CONFIG_OF
570static const struct of_device_id dryice_dt_ids[] = {
571 { .compatible = "fsl,imx25-rtc" },
572 { /* sentinel */ }
573};
574
575MODULE_DEVICE_TABLE(of, dryice_dt_ids);
576#endif
577
Baruch Siacheba54542010-08-10 18:02:13 -0700578static struct platform_driver dryice_rtc_driver = {
579 .driver = {
580 .name = "imxdi_rtc",
Roland Stigge968d21c2012-12-17 16:02:23 -0800581 .of_match_table = of_match_ptr(dryice_dt_ids),
Baruch Siacheba54542010-08-10 18:02:13 -0700582 },
Jingoo Han5073cba2013-04-29 16:18:24 -0700583 .remove = __exit_p(dryice_rtc_remove),
Baruch Siacheba54542010-08-10 18:02:13 -0700584};
585
Jingoo Han61534342013-04-29 16:18:42 -0700586module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe);
Baruch Siacheba54542010-08-10 18:02:13 -0700587
588MODULE_AUTHOR("Freescale Semiconductor, Inc.");
589MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
590MODULE_DESCRIPTION("IMX DryIce Realtime Clock Driver (RTC)");
591MODULE_LICENSE("GPL");