blob: dddaa60871b98cac8c950dc9a97a4f97529725fd [file] [log] [blame]
David Brownelldb68b182006-12-06 20:38:36 -08001/*
Johan Hovold10211ae2014-12-10 15:53:19 -08002 * TI OMAP Real Time Clock interface for Linux
David Brownelldb68b182006-12-06 20:38:36 -08003 *
4 * Copyright (C) 2003 MontaVista Software, Inc.
5 * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
6 *
7 * Copyright (C) 2006 David Brownell (new RTC framework)
Johan Hovold01251382014-12-10 15:53:22 -08008 * Copyright (C) 2014 Johan Hovold <johan@kernel.org>
David Brownelldb68b182006-12-06 20:38:36 -08009 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
14 */
15
Marcin Niestroj97ea1902016-09-16 11:26:28 +020016#include <dt-bindings/gpio/gpio.h>
David Brownelldb68b182006-12-06 20:38:36 -080017#include <linux/bcd.h>
Marcin Niestroj97ea1902016-09-16 11:26:28 +020018#include <linux/clk.h>
19#include <linux/delay.h>
20#include <linux/init.h>
21#include <linux/io.h>
22#include <linux/ioport.h>
23#include <linux/kernel.h>
24#include <linux/module.h>
Afzal Mohammed9e0344d2012-12-17 16:02:15 -080025#include <linux/of.h>
26#include <linux/of_device.h>
Marcin Niestroj97ea1902016-09-16 11:26:28 +020027#include <linux/pinctrl/pinctrl.h>
28#include <linux/pinctrl/pinconf.h>
29#include <linux/pinctrl/pinconf-generic.h>
30#include <linux/platform_device.h>
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -080031#include <linux/pm_runtime.h>
Marcin Niestroj97ea1902016-09-16 11:26:28 +020032#include <linux/rtc.h>
David Brownelldb68b182006-12-06 20:38:36 -080033
Johan Hovold10211ae2014-12-10 15:53:19 -080034/*
35 * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
David Brownelldb68b182006-12-06 20:38:36 -080036 * with century-range alarm matching, driven by the 32kHz clock.
37 *
38 * The main user-visible ways it differs from PC RTCs are by omitting
39 * "don't care" alarm fields and sub-second periodic IRQs, and having
40 * an autoadjust mechanism to calibrate to the true oscillator rate.
41 *
42 * Board-specific wiring options include using split power mode with
43 * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset),
44 * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from
Sekhar Norifa5b0782010-10-27 15:33:05 -070045 * low power modes) for OMAP1 boards (OMAP-L138 has this built into
46 * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment.
David Brownelldb68b182006-12-06 20:38:36 -080047 */
48
David Brownelldb68b182006-12-06 20:38:36 -080049/* RTC registers */
50#define OMAP_RTC_SECONDS_REG 0x00
51#define OMAP_RTC_MINUTES_REG 0x04
52#define OMAP_RTC_HOURS_REG 0x08
53#define OMAP_RTC_DAYS_REG 0x0C
54#define OMAP_RTC_MONTHS_REG 0x10
55#define OMAP_RTC_YEARS_REG 0x14
56#define OMAP_RTC_WEEKS_REG 0x18
57
58#define OMAP_RTC_ALARM_SECONDS_REG 0x20
59#define OMAP_RTC_ALARM_MINUTES_REG 0x24
60#define OMAP_RTC_ALARM_HOURS_REG 0x28
61#define OMAP_RTC_ALARM_DAYS_REG 0x2c
62#define OMAP_RTC_ALARM_MONTHS_REG 0x30
63#define OMAP_RTC_ALARM_YEARS_REG 0x34
64
65#define OMAP_RTC_CTRL_REG 0x40
66#define OMAP_RTC_STATUS_REG 0x44
67#define OMAP_RTC_INTERRUPTS_REG 0x48
68
69#define OMAP_RTC_COMP_LSB_REG 0x4c
70#define OMAP_RTC_COMP_MSB_REG 0x50
71#define OMAP_RTC_OSC_REG 0x54
72
Afzal Mohammedcab14582012-12-17 16:02:11 -080073#define OMAP_RTC_KICK0_REG 0x6c
74#define OMAP_RTC_KICK1_REG 0x70
75
Hebbar Gururaja8af750e2013-09-11 14:24:18 -070076#define OMAP_RTC_IRQWAKEEN 0x7c
77
Johan Hovold222a12f2014-12-10 15:53:13 -080078#define OMAP_RTC_ALARM2_SECONDS_REG 0x80
79#define OMAP_RTC_ALARM2_MINUTES_REG 0x84
80#define OMAP_RTC_ALARM2_HOURS_REG 0x88
81#define OMAP_RTC_ALARM2_DAYS_REG 0x8c
82#define OMAP_RTC_ALARM2_MONTHS_REG 0x90
83#define OMAP_RTC_ALARM2_YEARS_REG 0x94
84
85#define OMAP_RTC_PMIC_REG 0x98
86
David Brownelldb68b182006-12-06 20:38:36 -080087/* OMAP_RTC_CTRL_REG bit fields: */
Sekhar Nori92adb962014-06-06 14:36:05 -070088#define OMAP_RTC_CTRL_SPLIT BIT(7)
89#define OMAP_RTC_CTRL_DISABLE BIT(6)
90#define OMAP_RTC_CTRL_SET_32_COUNTER BIT(5)
91#define OMAP_RTC_CTRL_TEST BIT(4)
92#define OMAP_RTC_CTRL_MODE_12_24 BIT(3)
93#define OMAP_RTC_CTRL_AUTO_COMP BIT(2)
94#define OMAP_RTC_CTRL_ROUND_30S BIT(1)
95#define OMAP_RTC_CTRL_STOP BIT(0)
David Brownelldb68b182006-12-06 20:38:36 -080096
97/* OMAP_RTC_STATUS_REG bit fields: */
Sekhar Nori92adb962014-06-06 14:36:05 -070098#define OMAP_RTC_STATUS_POWER_UP BIT(7)
Johan Hovold222a12f2014-12-10 15:53:13 -080099#define OMAP_RTC_STATUS_ALARM2 BIT(7)
Sekhar Nori92adb962014-06-06 14:36:05 -0700100#define OMAP_RTC_STATUS_ALARM BIT(6)
101#define OMAP_RTC_STATUS_1D_EVENT BIT(5)
102#define OMAP_RTC_STATUS_1H_EVENT BIT(4)
103#define OMAP_RTC_STATUS_1M_EVENT BIT(3)
104#define OMAP_RTC_STATUS_1S_EVENT BIT(2)
105#define OMAP_RTC_STATUS_RUN BIT(1)
106#define OMAP_RTC_STATUS_BUSY BIT(0)
David Brownelldb68b182006-12-06 20:38:36 -0800107
108/* OMAP_RTC_INTERRUPTS_REG bit fields: */
Johan Hovold222a12f2014-12-10 15:53:13 -0800109#define OMAP_RTC_INTERRUPTS_IT_ALARM2 BIT(4)
Sekhar Nori92adb962014-06-06 14:36:05 -0700110#define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3)
111#define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2)
David Brownelldb68b182006-12-06 20:38:36 -0800112
Sekhar Noricd914bb2014-06-06 14:36:06 -0700113/* OMAP_RTC_OSC_REG bit fields: */
114#define OMAP_RTC_OSC_32KCLK_EN BIT(6)
Keerthy399cf0f2015-08-18 15:11:16 +0530115#define OMAP_RTC_OSC_SEL_32KCLK_SRC BIT(3)
Lokesh Vutla39849032016-10-27 11:27:25 +0530116#define OMAP_RTC_OSC_OSC32K_GZ_DISABLE BIT(4)
Sekhar Noricd914bb2014-06-06 14:36:06 -0700117
Hebbar Gururaja8af750e2013-09-11 14:24:18 -0700118/* OMAP_RTC_IRQWAKEEN bit fields: */
Sekhar Nori92adb962014-06-06 14:36:05 -0700119#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1)
Hebbar Gururaja8af750e2013-09-11 14:24:18 -0700120
Johan Hovold222a12f2014-12-10 15:53:13 -0800121/* OMAP_RTC_PMIC bit fields: */
122#define OMAP_RTC_PMIC_POWER_EN_EN BIT(16)
Marcin Niestroj97ea1902016-09-16 11:26:28 +0200123#define OMAP_RTC_PMIC_EXT_WKUP_EN(x) BIT(x)
124#define OMAP_RTC_PMIC_EXT_WKUP_POL(x) BIT(4 + x)
Johan Hovold222a12f2014-12-10 15:53:13 -0800125
Afzal Mohammedcab14582012-12-17 16:02:11 -0800126/* OMAP_RTC_KICKER values */
127#define KICK0_VALUE 0x83e70b13
128#define KICK1_VALUE 0x95a4f1e0
129
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700130struct omap_rtc;
131
Johan Hovold2153f942014-12-10 15:53:01 -0800132struct omap_rtc_device_type {
133 bool has_32kclk_en;
Johan Hovold2153f942014-12-10 15:53:01 -0800134 bool has_irqwakeen;
Johan Hovold222a12f2014-12-10 15:53:13 -0800135 bool has_pmic_mode;
Johan Hovold9291e342014-12-10 15:53:04 -0800136 bool has_power_up_reset;
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700137 void (*lock)(struct omap_rtc *rtc);
138 void (*unlock)(struct omap_rtc *rtc);
Johan Hovold2153f942014-12-10 15:53:01 -0800139};
Sekhar Noricd914bb2014-06-06 14:36:06 -0700140
Johan Hovold55ba9532014-12-10 15:52:55 -0800141struct omap_rtc {
142 struct rtc_device *rtc;
143 void __iomem *base;
Keerthy532409a2015-08-18 15:11:15 +0530144 struct clk *clk;
Johan Hovold55ba9532014-12-10 15:52:55 -0800145 int irq_alarm;
146 int irq_timer;
147 u8 interrupts_reg;
Johan Hovold222a12f2014-12-10 15:53:13 -0800148 bool is_pmic_controller;
Keerthy399cf0f2015-08-18 15:11:16 +0530149 bool has_ext_clk;
Johan Hovold2153f942014-12-10 15:53:01 -0800150 const struct omap_rtc_device_type *type;
Marcin Niestroj97ea1902016-09-16 11:26:28 +0200151 struct pinctrl_dev *pctldev;
Johan Hovold55ba9532014-12-10 15:52:55 -0800152};
David Brownelldb68b182006-12-06 20:38:36 -0800153
Johan Hovold55ba9532014-12-10 15:52:55 -0800154static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg)
155{
156 return readb(rtc->base + reg);
157}
Afzal Mohammedcab14582012-12-17 16:02:11 -0800158
Johan Hovoldc253a892014-12-10 15:53:10 -0800159static inline u32 rtc_readl(struct omap_rtc *rtc, unsigned int reg)
160{
161 return readl(rtc->base + reg);
162}
163
Johan Hovold55ba9532014-12-10 15:52:55 -0800164static inline void rtc_write(struct omap_rtc *rtc, unsigned int reg, u8 val)
165{
166 writeb(val, rtc->base + reg);
167}
David Brownelldb68b182006-12-06 20:38:36 -0800168
Johan Hovold55ba9532014-12-10 15:52:55 -0800169static inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val)
170{
171 writel(val, rtc->base + reg);
172}
David Brownelldb68b182006-12-06 20:38:36 -0800173
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700174static void am3352_rtc_unlock(struct omap_rtc *rtc)
175{
176 rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE);
177 rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE);
178}
179
180static void am3352_rtc_lock(struct omap_rtc *rtc)
181{
182 rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0);
183 rtc_writel(rtc, OMAP_RTC_KICK1_REG, 0);
184}
185
186static void default_rtc_unlock(struct omap_rtc *rtc)
187{
188}
189
190static void default_rtc_lock(struct omap_rtc *rtc)
191{
192}
193
Johan Hovold10211ae2014-12-10 15:53:19 -0800194/*
195 * We rely on the rtc framework to handle locking (rtc->ops_lock),
David Brownelldb68b182006-12-06 20:38:36 -0800196 * so the only other requirement is that register accesses which
197 * require BUSY to be clear are made with IRQs locally disabled
198 */
Johan Hovold55ba9532014-12-10 15:52:55 -0800199static void rtc_wait_not_busy(struct omap_rtc *rtc)
David Brownelldb68b182006-12-06 20:38:36 -0800200{
Johan Hovold10211ae2014-12-10 15:53:19 -0800201 int count;
202 u8 status;
David Brownelldb68b182006-12-06 20:38:36 -0800203
204 /* BUSY may stay active for 1/32768 second (~30 usec) */
205 for (count = 0; count < 50; count++) {
Johan Hovold55ba9532014-12-10 15:52:55 -0800206 status = rtc_read(rtc, OMAP_RTC_STATUS_REG);
Johan Hovold10211ae2014-12-10 15:53:19 -0800207 if (!(status & OMAP_RTC_STATUS_BUSY))
David Brownelldb68b182006-12-06 20:38:36 -0800208 break;
209 udelay(1);
210 }
211 /* now we have ~15 usec to read/write various registers */
212}
213
Johan Hovold55ba9532014-12-10 15:52:55 -0800214static irqreturn_t rtc_irq(int irq, void *dev_id)
David Brownelldb68b182006-12-06 20:38:36 -0800215{
Johan Hovold10211ae2014-12-10 15:53:19 -0800216 struct omap_rtc *rtc = dev_id;
217 unsigned long events = 0;
218 u8 irq_data;
David Brownelldb68b182006-12-06 20:38:36 -0800219
Johan Hovold55ba9532014-12-10 15:52:55 -0800220 irq_data = rtc_read(rtc, OMAP_RTC_STATUS_REG);
David Brownelldb68b182006-12-06 20:38:36 -0800221
222 /* alarm irq? */
223 if (irq_data & OMAP_RTC_STATUS_ALARM) {
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700224 rtc->type->unlock(rtc);
Johan Hovold55ba9532014-12-10 15:52:55 -0800225 rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700226 rtc->type->lock(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800227 events |= RTC_IRQF | RTC_AF;
228 }
229
230 /* 1/sec periodic/update irq? */
231 if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
232 events |= RTC_IRQF | RTC_UF;
233
Johan Hovold55ba9532014-12-10 15:52:55 -0800234 rtc_update_irq(rtc->rtc, 1, events);
David Brownelldb68b182006-12-06 20:38:36 -0800235
236 return IRQ_HANDLED;
237}
238
John Stultz16380c12011-02-02 17:02:41 -0800239static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
240{
Johan Hovold55ba9532014-12-10 15:52:55 -0800241 struct omap_rtc *rtc = dev_get_drvdata(dev);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700242 u8 reg, irqwake_reg = 0;
John Stultz16380c12011-02-02 17:02:41 -0800243
244 local_irq_disable();
Johan Hovold55ba9532014-12-10 15:52:55 -0800245 rtc_wait_not_busy(rtc);
246 reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
Johan Hovold2153f942014-12-10 15:53:01 -0800247 if (rtc->type->has_irqwakeen)
Johan Hovold55ba9532014-12-10 15:52:55 -0800248 irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700249
250 if (enabled) {
John Stultz16380c12011-02-02 17:02:41 -0800251 reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700252 irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
253 } else {
John Stultz16380c12011-02-02 17:02:41 -0800254 reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700255 irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
256 }
Johan Hovold55ba9532014-12-10 15:52:55 -0800257 rtc_wait_not_busy(rtc);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700258 rtc->type->unlock(rtc);
Johan Hovold55ba9532014-12-10 15:52:55 -0800259 rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
Johan Hovold2153f942014-12-10 15:53:01 -0800260 if (rtc->type->has_irqwakeen)
Johan Hovold55ba9532014-12-10 15:52:55 -0800261 rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700262 rtc->type->lock(rtc);
John Stultz16380c12011-02-02 17:02:41 -0800263 local_irq_enable();
264
265 return 0;
266}
267
David Brownelldb68b182006-12-06 20:38:36 -0800268/* this hardware doesn't support "don't care" alarm fields */
269static int tm2bcd(struct rtc_time *tm)
270{
271 if (rtc_valid_tm(tm) != 0)
272 return -EINVAL;
273
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700274 tm->tm_sec = bin2bcd(tm->tm_sec);
275 tm->tm_min = bin2bcd(tm->tm_min);
276 tm->tm_hour = bin2bcd(tm->tm_hour);
277 tm->tm_mday = bin2bcd(tm->tm_mday);
David Brownelldb68b182006-12-06 20:38:36 -0800278
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700279 tm->tm_mon = bin2bcd(tm->tm_mon + 1);
David Brownelldb68b182006-12-06 20:38:36 -0800280
281 /* epoch == 1900 */
282 if (tm->tm_year < 100 || tm->tm_year > 199)
283 return -EINVAL;
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700284 tm->tm_year = bin2bcd(tm->tm_year - 100);
David Brownelldb68b182006-12-06 20:38:36 -0800285
286 return 0;
287}
288
289static void bcd2tm(struct rtc_time *tm)
290{
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700291 tm->tm_sec = bcd2bin(tm->tm_sec);
292 tm->tm_min = bcd2bin(tm->tm_min);
293 tm->tm_hour = bcd2bin(tm->tm_hour);
294 tm->tm_mday = bcd2bin(tm->tm_mday);
295 tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
David Brownelldb68b182006-12-06 20:38:36 -0800296 /* epoch == 1900 */
Adrian Bunkfe20ba72008-10-18 20:28:41 -0700297 tm->tm_year = bcd2bin(tm->tm_year) + 100;
David Brownelldb68b182006-12-06 20:38:36 -0800298}
299
Johan Hovoldcbbe3262014-12-10 15:53:07 -0800300static void omap_rtc_read_time_raw(struct omap_rtc *rtc, struct rtc_time *tm)
301{
302 tm->tm_sec = rtc_read(rtc, OMAP_RTC_SECONDS_REG);
303 tm->tm_min = rtc_read(rtc, OMAP_RTC_MINUTES_REG);
304 tm->tm_hour = rtc_read(rtc, OMAP_RTC_HOURS_REG);
305 tm->tm_mday = rtc_read(rtc, OMAP_RTC_DAYS_REG);
306 tm->tm_mon = rtc_read(rtc, OMAP_RTC_MONTHS_REG);
307 tm->tm_year = rtc_read(rtc, OMAP_RTC_YEARS_REG);
308}
David Brownelldb68b182006-12-06 20:38:36 -0800309
310static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
311{
Johan Hovold55ba9532014-12-10 15:52:55 -0800312 struct omap_rtc *rtc = dev_get_drvdata(dev);
313
David Brownelldb68b182006-12-06 20:38:36 -0800314 /* we don't report wday/yday/isdst ... */
315 local_irq_disable();
Johan Hovold55ba9532014-12-10 15:52:55 -0800316 rtc_wait_not_busy(rtc);
Johan Hovoldcbbe3262014-12-10 15:53:07 -0800317 omap_rtc_read_time_raw(rtc, tm);
David Brownelldb68b182006-12-06 20:38:36 -0800318 local_irq_enable();
319
320 bcd2tm(tm);
Johan Hovold10211ae2014-12-10 15:53:19 -0800321
David Brownelldb68b182006-12-06 20:38:36 -0800322 return 0;
323}
324
325static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
326{
Johan Hovold55ba9532014-12-10 15:52:55 -0800327 struct omap_rtc *rtc = dev_get_drvdata(dev);
328
David Brownelldb68b182006-12-06 20:38:36 -0800329 if (tm2bcd(tm) < 0)
330 return -EINVAL;
Johan Hovold10211ae2014-12-10 15:53:19 -0800331
David Brownelldb68b182006-12-06 20:38:36 -0800332 local_irq_disable();
Johan Hovold55ba9532014-12-10 15:52:55 -0800333 rtc_wait_not_busy(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800334
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700335 rtc->type->unlock(rtc);
Johan Hovold55ba9532014-12-10 15:52:55 -0800336 rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year);
337 rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon);
338 rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday);
339 rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour);
340 rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min);
341 rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700342 rtc->type->lock(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800343
344 local_irq_enable();
345
346 return 0;
347}
348
349static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
350{
Johan Hovold55ba9532014-12-10 15:52:55 -0800351 struct omap_rtc *rtc = dev_get_drvdata(dev);
Johan Hovold10211ae2014-12-10 15:53:19 -0800352 u8 interrupts;
David Brownelldb68b182006-12-06 20:38:36 -0800353
Johan Hovold55ba9532014-12-10 15:52:55 -0800354 local_irq_disable();
355 rtc_wait_not_busy(rtc);
356
357 alm->time.tm_sec = rtc_read(rtc, OMAP_RTC_ALARM_SECONDS_REG);
358 alm->time.tm_min = rtc_read(rtc, OMAP_RTC_ALARM_MINUTES_REG);
359 alm->time.tm_hour = rtc_read(rtc, OMAP_RTC_ALARM_HOURS_REG);
360 alm->time.tm_mday = rtc_read(rtc, OMAP_RTC_ALARM_DAYS_REG);
361 alm->time.tm_mon = rtc_read(rtc, OMAP_RTC_ALARM_MONTHS_REG);
362 alm->time.tm_year = rtc_read(rtc, OMAP_RTC_ALARM_YEARS_REG);
David Brownelldb68b182006-12-06 20:38:36 -0800363
364 local_irq_enable();
365
366 bcd2tm(&alm->time);
Johan Hovold10211ae2014-12-10 15:53:19 -0800367
368 interrupts = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
369 alm->enabled = !!(interrupts & OMAP_RTC_INTERRUPTS_IT_ALARM);
David Brownelldb68b182006-12-06 20:38:36 -0800370
371 return 0;
372}
373
374static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
375{
Johan Hovold55ba9532014-12-10 15:52:55 -0800376 struct omap_rtc *rtc = dev_get_drvdata(dev);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700377 u8 reg, irqwake_reg = 0;
David Brownelldb68b182006-12-06 20:38:36 -0800378
David Brownelldb68b182006-12-06 20:38:36 -0800379 if (tm2bcd(&alm->time) < 0)
380 return -EINVAL;
381
382 local_irq_disable();
Johan Hovold55ba9532014-12-10 15:52:55 -0800383 rtc_wait_not_busy(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800384
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700385 rtc->type->unlock(rtc);
Johan Hovold55ba9532014-12-10 15:52:55 -0800386 rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year);
387 rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon);
388 rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday);
389 rtc_write(rtc, OMAP_RTC_ALARM_HOURS_REG, alm->time.tm_hour);
390 rtc_write(rtc, OMAP_RTC_ALARM_MINUTES_REG, alm->time.tm_min);
391 rtc_write(rtc, OMAP_RTC_ALARM_SECONDS_REG, alm->time.tm_sec);
David Brownelldb68b182006-12-06 20:38:36 -0800392
Johan Hovold55ba9532014-12-10 15:52:55 -0800393 reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
Johan Hovold2153f942014-12-10 15:53:01 -0800394 if (rtc->type->has_irqwakeen)
Johan Hovold55ba9532014-12-10 15:52:55 -0800395 irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700396
397 if (alm->enabled) {
David Brownelldb68b182006-12-06 20:38:36 -0800398 reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700399 irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
400 } else {
David Brownelldb68b182006-12-06 20:38:36 -0800401 reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700402 irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
403 }
Johan Hovold55ba9532014-12-10 15:52:55 -0800404 rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
Johan Hovold2153f942014-12-10 15:53:01 -0800405 if (rtc->type->has_irqwakeen)
Johan Hovold55ba9532014-12-10 15:52:55 -0800406 rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700407 rtc->type->lock(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800408
409 local_irq_enable();
410
411 return 0;
412}
413
Johan Hovold222a12f2014-12-10 15:53:13 -0800414static struct omap_rtc *omap_rtc_power_off_rtc;
415
416/*
417 * omap_rtc_poweroff: RTC-controlled power off
418 *
419 * The RTC can be used to control an external PMIC via the pmic_power_en pin,
420 * which can be configured to transition to OFF on ALARM2 events.
421 *
422 * Notes:
423 * The two-second alarm offset is the shortest offset possible as the alarm
424 * registers must be set before the next timer update and the offset
425 * calculation is too heavy for everything to be done within a single access
426 * period (~15 us).
427 *
428 * Called with local interrupts disabled.
429 */
430static void omap_rtc_power_off(void)
431{
432 struct omap_rtc *rtc = omap_rtc_power_off_rtc;
433 struct rtc_time tm;
434 unsigned long now;
435 u32 val;
436
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700437 rtc->type->unlock(rtc);
Johan Hovold222a12f2014-12-10 15:53:13 -0800438 /* enable pmic_power_en control */
439 val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
440 rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
441
442 /* set alarm two seconds from now */
443 omap_rtc_read_time_raw(rtc, &tm);
444 bcd2tm(&tm);
445 rtc_tm_to_time(&tm, &now);
446 rtc_time_to_tm(now + 2, &tm);
447
448 if (tm2bcd(&tm) < 0) {
449 dev_err(&rtc->rtc->dev, "power off failed\n");
450 return;
451 }
452
453 rtc_wait_not_busy(rtc);
454
455 rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec);
456 rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min);
457 rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour);
458 rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday);
459 rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon);
460 rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year);
461
462 /*
463 * enable ALARM2 interrupt
464 *
465 * NOTE: this fails on AM3352 if rtc_write (writeb) is used
466 */
467 val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
468 rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG,
469 val | OMAP_RTC_INTERRUPTS_IT_ALARM2);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700470 rtc->type->lock(rtc);
Johan Hovold222a12f2014-12-10 15:53:13 -0800471
472 /*
473 * Wait for alarm to trigger (within two seconds) and external PMIC to
474 * power off the system. Add a 500 ms margin for external latencies
475 * (e.g. debounce circuits).
476 */
477 mdelay(2500);
478}
479
Julia Lawall34c7b3a2016-08-31 10:05:25 +0200480static const struct rtc_class_ops omap_rtc_ops = {
David Brownelldb68b182006-12-06 20:38:36 -0800481 .read_time = omap_rtc_read_time,
482 .set_time = omap_rtc_set_time,
483 .read_alarm = omap_rtc_read_alarm,
484 .set_alarm = omap_rtc_set_alarm,
John Stultz16380c12011-02-02 17:02:41 -0800485 .alarm_irq_enable = omap_rtc_alarm_irq_enable,
David Brownelldb68b182006-12-06 20:38:36 -0800486};
487
Johan Hovold2153f942014-12-10 15:53:01 -0800488static const struct omap_rtc_device_type omap_rtc_default_type = {
Johan Hovold9291e342014-12-10 15:53:04 -0800489 .has_power_up_reset = true,
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700490 .lock = default_rtc_lock,
491 .unlock = default_rtc_unlock,
Johan Hovold2153f942014-12-10 15:53:01 -0800492};
Afzal Mohammed9e0344d2012-12-17 16:02:15 -0800493
Johan Hovold2153f942014-12-10 15:53:01 -0800494static const struct omap_rtc_device_type omap_rtc_am3352_type = {
495 .has_32kclk_en = true,
Johan Hovold2153f942014-12-10 15:53:01 -0800496 .has_irqwakeen = true,
Johan Hovold222a12f2014-12-10 15:53:13 -0800497 .has_pmic_mode = true,
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700498 .lock = am3352_rtc_lock,
499 .unlock = am3352_rtc_unlock,
Johan Hovold2153f942014-12-10 15:53:01 -0800500};
501
502static const struct omap_rtc_device_type omap_rtc_da830_type = {
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700503 .lock = am3352_rtc_lock,
504 .unlock = am3352_rtc_unlock,
Johan Hovold2153f942014-12-10 15:53:01 -0800505};
506
507static const struct platform_device_id omap_rtc_id_table[] = {
Afzal Mohammedcab14582012-12-17 16:02:11 -0800508 {
Johan Hovolda430ca22014-12-10 15:52:58 -0800509 .name = "omap_rtc",
Johan Hovold2153f942014-12-10 15:53:01 -0800510 .driver_data = (kernel_ulong_t)&omap_rtc_default_type,
511 }, {
Hebbar Gururaja8af750e2013-09-11 14:24:18 -0700512 .name = "am3352-rtc",
Johan Hovold2153f942014-12-10 15:53:01 -0800513 .driver_data = (kernel_ulong_t)&omap_rtc_am3352_type,
514 }, {
Afzal Mohammedcab14582012-12-17 16:02:11 -0800515 .name = "da830-rtc",
Johan Hovold2153f942014-12-10 15:53:01 -0800516 .driver_data = (kernel_ulong_t)&omap_rtc_da830_type,
517 }, {
518 /* sentinel */
519 }
Afzal Mohammedcab14582012-12-17 16:02:11 -0800520};
Johan Hovold2153f942014-12-10 15:53:01 -0800521MODULE_DEVICE_TABLE(platform, omap_rtc_id_table);
Afzal Mohammedcab14582012-12-17 16:02:11 -0800522
Afzal Mohammed9e0344d2012-12-17 16:02:15 -0800523static const struct of_device_id omap_rtc_of_match[] = {
Johan Hovold2153f942014-12-10 15:53:01 -0800524 {
525 .compatible = "ti,am3352-rtc",
526 .data = &omap_rtc_am3352_type,
527 }, {
528 .compatible = "ti,da830-rtc",
529 .data = &omap_rtc_da830_type,
530 }, {
531 /* sentinel */
532 }
Afzal Mohammed9e0344d2012-12-17 16:02:15 -0800533};
534MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
535
Marcin Niestroj97ea1902016-09-16 11:26:28 +0200536static const struct pinctrl_pin_desc rtc_pins_desc[] = {
537 PINCTRL_PIN(0, "ext_wakeup0"),
538 PINCTRL_PIN(1, "ext_wakeup1"),
539 PINCTRL_PIN(2, "ext_wakeup2"),
540 PINCTRL_PIN(3, "ext_wakeup3"),
541};
542
543static int rtc_pinctrl_get_groups_count(struct pinctrl_dev *pctldev)
544{
545 return 0;
546}
547
548static const char *rtc_pinctrl_get_group_name(struct pinctrl_dev *pctldev,
549 unsigned int group)
550{
551 return NULL;
552}
553
554static const struct pinctrl_ops rtc_pinctrl_ops = {
555 .get_groups_count = rtc_pinctrl_get_groups_count,
556 .get_group_name = rtc_pinctrl_get_group_name,
557 .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
558 .dt_free_map = pinconf_generic_dt_free_map,
559};
560
561enum rtc_pin_config_param {
562 PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1,
563};
564
565static const struct pinconf_generic_params rtc_params[] = {
566 {"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0},
567};
568
569#ifdef CONFIG_DEBUG_FS
570static const struct pin_config_item rtc_conf_items[ARRAY_SIZE(rtc_params)] = {
571 PCONFDUMP(PIN_CONFIG_ACTIVE_HIGH, "input active high", NULL, false),
572};
573#endif
574
575static int rtc_pinconf_get(struct pinctrl_dev *pctldev,
576 unsigned int pin, unsigned long *config)
577{
578 struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
579 unsigned int param = pinconf_to_config_param(*config);
580 u32 val;
581 u16 arg = 0;
582
583 rtc->type->unlock(rtc);
584 val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
585 rtc->type->lock(rtc);
586
587 switch (param) {
588 case PIN_CONFIG_INPUT_ENABLE:
589 if (!(val & OMAP_RTC_PMIC_EXT_WKUP_EN(pin)))
590 return -EINVAL;
591 break;
592 case PIN_CONFIG_ACTIVE_HIGH:
593 if (val & OMAP_RTC_PMIC_EXT_WKUP_POL(pin))
594 return -EINVAL;
595 break;
596 default:
597 return -ENOTSUPP;
598 };
599
600 *config = pinconf_to_config_packed(param, arg);
601
602 return 0;
603}
604
605static int rtc_pinconf_set(struct pinctrl_dev *pctldev,
606 unsigned int pin, unsigned long *configs,
607 unsigned int num_configs)
608{
609 struct omap_rtc *rtc = pinctrl_dev_get_drvdata(pctldev);
610 u32 val;
611 unsigned int param;
612 u16 param_val;
613 int i;
614
615 rtc->type->unlock(rtc);
616 val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
617 rtc->type->lock(rtc);
618
619 /* active low by default */
620 val |= OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
621
622 for (i = 0; i < num_configs; i++) {
623 param = pinconf_to_config_param(configs[i]);
624 param_val = pinconf_to_config_argument(configs[i]);
625
626 switch (param) {
627 case PIN_CONFIG_INPUT_ENABLE:
628 if (param_val)
629 val |= OMAP_RTC_PMIC_EXT_WKUP_EN(pin);
630 else
631 val &= ~OMAP_RTC_PMIC_EXT_WKUP_EN(pin);
632 break;
633 case PIN_CONFIG_ACTIVE_HIGH:
634 val &= ~OMAP_RTC_PMIC_EXT_WKUP_POL(pin);
635 break;
636 default:
637 dev_err(&rtc->rtc->dev, "Property %u not supported\n",
638 param);
639 return -ENOTSUPP;
640 }
641 }
642
643 rtc->type->unlock(rtc);
644 rtc_writel(rtc, OMAP_RTC_PMIC_REG, val);
645 rtc->type->lock(rtc);
646
647 return 0;
648}
649
650static const struct pinconf_ops rtc_pinconf_ops = {
651 .is_generic = true,
652 .pin_config_get = rtc_pinconf_get,
653 .pin_config_set = rtc_pinconf_set,
654};
655
656static struct pinctrl_desc rtc_pinctrl_desc = {
657 .pins = rtc_pins_desc,
658 .npins = ARRAY_SIZE(rtc_pins_desc),
659 .pctlops = &rtc_pinctrl_ops,
660 .confops = &rtc_pinconf_ops,
661 .custom_params = rtc_params,
662 .num_custom_params = ARRAY_SIZE(rtc_params),
663#ifdef CONFIG_DEBUG_FS
664 .custom_conf_items = rtc_conf_items,
665#endif
666 .owner = THIS_MODULE,
667};
668
Lokesh Vutla5d9094b2015-04-16 12:46:05 -0700669static int omap_rtc_probe(struct platform_device *pdev)
David Brownelldb68b182006-12-06 20:38:36 -0800670{
Johan Hovold10211ae2014-12-10 15:53:19 -0800671 struct omap_rtc *rtc;
672 struct resource *res;
673 u8 reg, mask, new_ctrl;
Afzal Mohammedcab14582012-12-17 16:02:11 -0800674 const struct platform_device_id *id_entry;
Afzal Mohammed9e0344d2012-12-17 16:02:15 -0800675 const struct of_device_id *of_id;
Johan Hovold437b37a2014-12-10 15:52:40 -0800676 int ret;
Afzal Mohammed9e0344d2012-12-17 16:02:15 -0800677
Johan Hovold55ba9532014-12-10 15:52:55 -0800678 rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
679 if (!rtc)
680 return -ENOMEM;
681
Afzal Mohammed9e0344d2012-12-17 16:02:15 -0800682 of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
Johan Hovold2153f942014-12-10 15:53:01 -0800683 if (of_id) {
684 rtc->type = of_id->data;
Johan Hovold222a12f2014-12-10 15:53:13 -0800685 rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
686 of_property_read_bool(pdev->dev.of_node,
Johan Hovold094d3ee2014-12-10 15:54:14 -0800687 "system-power-controller");
Johan Hovold2153f942014-12-10 15:53:01 -0800688 } else {
689 id_entry = platform_get_device_id(pdev);
690 rtc->type = (void *)id_entry->driver_data;
Sekhar Nori337b6002014-06-06 14:36:04 -0700691 }
692
Johan Hovold55ba9532014-12-10 15:52:55 -0800693 rtc->irq_timer = platform_get_irq(pdev, 0);
694 if (rtc->irq_timer <= 0)
David Brownelldb68b182006-12-06 20:38:36 -0800695 return -ENOENT;
David Brownelldb68b182006-12-06 20:38:36 -0800696
Johan Hovold55ba9532014-12-10 15:52:55 -0800697 rtc->irq_alarm = platform_get_irq(pdev, 1);
698 if (rtc->irq_alarm <= 0)
David Brownelldb68b182006-12-06 20:38:36 -0800699 return -ENOENT;
David Brownelldb68b182006-12-06 20:38:36 -0800700
Keerthy399cf0f2015-08-18 15:11:16 +0530701 rtc->clk = devm_clk_get(&pdev->dev, "ext-clk");
702 if (!IS_ERR(rtc->clk))
703 rtc->has_ext_clk = true;
704 else
705 rtc->clk = devm_clk_get(&pdev->dev, "int-clk");
Keerthy532409a2015-08-18 15:11:15 +0530706
707 if (!IS_ERR(rtc->clk))
708 clk_prepare_enable(rtc->clk);
709
David Brownelldb68b182006-12-06 20:38:36 -0800710 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
Johan Hovold55ba9532014-12-10 15:52:55 -0800711 rtc->base = devm_ioremap_resource(&pdev->dev, res);
712 if (IS_ERR(rtc->base))
713 return PTR_ERR(rtc->base);
714
715 platform_set_drvdata(pdev, rtc);
Mark A. Greer8cfde8c2009-12-15 16:46:11 -0800716
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -0800717 /* Enable the clock/module so that we can access the registers */
718 pm_runtime_enable(&pdev->dev);
719 pm_runtime_get_sync(&pdev->dev);
720
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700721 rtc->type->unlock(rtc);
Afzal Mohammedcab14582012-12-17 16:02:11 -0800722
Johan Hovold1ed8b5d2014-12-10 15:52:36 -0800723 /*
724 * disable interrupts
725 *
726 * NOTE: ALARM2 is not cleared on AM3352 if rtc_write (writeb) is used
David Brownelldb68b182006-12-06 20:38:36 -0800727 */
Johan Hovold55ba9532014-12-10 15:52:55 -0800728 rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
David Brownelldb68b182006-12-06 20:38:36 -0800729
Sekhar Noricd914bb2014-06-06 14:36:06 -0700730 /* enable RTC functional clock */
Johan Hovold2153f942014-12-10 15:53:01 -0800731 if (rtc->type->has_32kclk_en) {
Johan Hovold55ba9532014-12-10 15:52:55 -0800732 reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
733 rtc_writel(rtc, OMAP_RTC_OSC_REG,
734 reg | OMAP_RTC_OSC_32KCLK_EN);
Johan Hovold44c63a52014-12-10 15:52:30 -0800735 }
Sekhar Noricd914bb2014-06-06 14:36:06 -0700736
David Brownelldb68b182006-12-06 20:38:36 -0800737 /* clear old status */
Johan Hovold55ba9532014-12-10 15:52:55 -0800738 reg = rtc_read(rtc, OMAP_RTC_STATUS_REG);
Johan Hovold9291e342014-12-10 15:53:04 -0800739
740 mask = OMAP_RTC_STATUS_ALARM;
741
Johan Hovold222a12f2014-12-10 15:53:13 -0800742 if (rtc->type->has_pmic_mode)
743 mask |= OMAP_RTC_STATUS_ALARM2;
744
Johan Hovold9291e342014-12-10 15:53:04 -0800745 if (rtc->type->has_power_up_reset) {
746 mask |= OMAP_RTC_STATUS_POWER_UP;
747 if (reg & OMAP_RTC_STATUS_POWER_UP)
748 dev_info(&pdev->dev, "RTC power up reset detected\n");
David Brownelldb68b182006-12-06 20:38:36 -0800749 }
Johan Hovold9291e342014-12-10 15:53:04 -0800750
751 if (reg & mask)
752 rtc_write(rtc, OMAP_RTC_STATUS_REG, reg & mask);
David Brownelldb68b182006-12-06 20:38:36 -0800753
David Brownelldb68b182006-12-06 20:38:36 -0800754 /* On boards with split power, RTC_ON_NOFF won't reset the RTC */
Johan Hovold55ba9532014-12-10 15:52:55 -0800755 reg = rtc_read(rtc, OMAP_RTC_CTRL_REG);
Johan Hovold10211ae2014-12-10 15:53:19 -0800756 if (reg & OMAP_RTC_CTRL_STOP)
Johan Hovold397b6302014-12-10 15:52:49 -0800757 dev_info(&pdev->dev, "already running\n");
David Brownelldb68b182006-12-06 20:38:36 -0800758
759 /* force to 24 hour mode */
Johan Hovold10211ae2014-12-10 15:53:19 -0800760 new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT | OMAP_RTC_CTRL_AUTO_COMP);
David Brownelldb68b182006-12-06 20:38:36 -0800761 new_ctrl |= OMAP_RTC_CTRL_STOP;
762
Johan Hovold10211ae2014-12-10 15:53:19 -0800763 /*
764 * BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
David Brownelldb68b182006-12-06 20:38:36 -0800765 *
Sekhar Norifa5b0782010-10-27 15:33:05 -0700766 * - Device wake-up capability setting should come through chip
767 * init logic. OMAP1 boards should initialize the "wakeup capable"
768 * flag in the platform device if the board is wired right for
769 * being woken up by RTC alarm. For OMAP-L138, this capability
770 * is built into the SoC by the "Deep Sleep" capability.
David Brownelldb68b182006-12-06 20:38:36 -0800771 *
772 * - Boards wired so RTC_ON_nOFF is used as the reset signal,
773 * rather than nPWRON_RESET, should forcibly enable split
774 * power mode. (Some chip errata report that RTC_CTRL_SPLIT
775 * is write-only, and always reads as zero...)
776 */
David Brownelldb68b182006-12-06 20:38:36 -0800777
Johan Hovold10211ae2014-12-10 15:53:19 -0800778 if (new_ctrl & OMAP_RTC_CTRL_SPLIT)
Johan Hovold397b6302014-12-10 15:52:49 -0800779 dev_info(&pdev->dev, "split power mode\n");
David Brownelldb68b182006-12-06 20:38:36 -0800780
781 if (reg != new_ctrl)
Johan Hovold55ba9532014-12-10 15:52:55 -0800782 rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl);
David Brownelldb68b182006-12-06 20:38:36 -0800783
Keerthy399cf0f2015-08-18 15:11:16 +0530784 /*
785 * If we have the external clock then switch to it so we can keep
786 * ticking across suspend.
787 */
788 if (rtc->has_ext_clk) {
789 reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
Lokesh Vutla39849032016-10-27 11:27:25 +0530790 reg &= ~OMAP_RTC_OSC_OSC32K_GZ_DISABLE;
791 reg |= OMAP_RTC_OSC_32KCLK_EN | OMAP_RTC_OSC_SEL_32KCLK_SRC;
792 rtc_writel(rtc, OMAP_RTC_OSC_REG, reg);
Keerthy399cf0f2015-08-18 15:11:16 +0530793 }
794
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700795 rtc->type->lock(rtc);
796
Johan Hovold4390ce02014-12-10 15:52:43 -0800797 device_init_wakeup(&pdev->dev, true);
798
Johan Hovold55ba9532014-12-10 15:52:55 -0800799 rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
Johan Hovold4390ce02014-12-10 15:52:43 -0800800 &omap_rtc_ops, THIS_MODULE);
Johan Hovold55ba9532014-12-10 15:52:55 -0800801 if (IS_ERR(rtc->rtc)) {
802 ret = PTR_ERR(rtc->rtc);
Johan Hovold4390ce02014-12-10 15:52:43 -0800803 goto err;
804 }
Johan Hovold4390ce02014-12-10 15:52:43 -0800805
806 /* handle periodic and alarm irqs */
Johan Hovold55ba9532014-12-10 15:52:55 -0800807 ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0,
808 dev_name(&rtc->rtc->dev), rtc);
Johan Hovold4390ce02014-12-10 15:52:43 -0800809 if (ret)
810 goto err;
811
Johan Hovold55ba9532014-12-10 15:52:55 -0800812 if (rtc->irq_timer != rtc->irq_alarm) {
813 ret = devm_request_irq(&pdev->dev, rtc->irq_alarm, rtc_irq, 0,
814 dev_name(&rtc->rtc->dev), rtc);
Johan Hovold4390ce02014-12-10 15:52:43 -0800815 if (ret)
816 goto err;
817 }
818
Johan Hovold222a12f2014-12-10 15:53:13 -0800819 if (rtc->is_pmic_controller) {
820 if (!pm_power_off) {
821 omap_rtc_power_off_rtc = rtc;
822 pm_power_off = omap_rtc_power_off;
823 }
824 }
825
Marcin Niestroj97ea1902016-09-16 11:26:28 +0200826 /* Support ext_wakeup pinconf */
827 rtc_pinctrl_desc.name = dev_name(&pdev->dev);
828
829 rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc);
830 if (IS_ERR(rtc->pctldev)) {
831 dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
832 return PTR_ERR(rtc->pctldev);
833 }
834
David Brownelldb68b182006-12-06 20:38:36 -0800835 return 0;
836
Johan Hovold437b37a2014-12-10 15:52:40 -0800837err:
Johan Hovold7ecd9a32014-12-10 15:52:33 -0800838 device_init_wakeup(&pdev->dev, false);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700839 rtc->type->lock(rtc);
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -0800840 pm_runtime_put_sync(&pdev->dev);
841 pm_runtime_disable(&pdev->dev);
Johan Hovold437b37a2014-12-10 15:52:40 -0800842
843 return ret;
David Brownelldb68b182006-12-06 20:38:36 -0800844}
845
David Brownell71fc8222008-07-23 21:30:38 -0700846static int __exit omap_rtc_remove(struct platform_device *pdev)
David Brownelldb68b182006-12-06 20:38:36 -0800847{
Johan Hovold55ba9532014-12-10 15:52:55 -0800848 struct omap_rtc *rtc = platform_get_drvdata(pdev);
Keerthy399cf0f2015-08-18 15:11:16 +0530849 u8 reg;
David Brownelldb68b182006-12-06 20:38:36 -0800850
Johan Hovold222a12f2014-12-10 15:53:13 -0800851 if (pm_power_off == omap_rtc_power_off &&
852 omap_rtc_power_off_rtc == rtc) {
853 pm_power_off = NULL;
854 omap_rtc_power_off_rtc = NULL;
855 }
856
David Brownelldb68b182006-12-06 20:38:36 -0800857 device_init_wakeup(&pdev->dev, 0);
858
Keerthy532409a2015-08-18 15:11:15 +0530859 if (!IS_ERR(rtc->clk))
860 clk_disable_unprepare(rtc->clk);
861
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700862 rtc->type->unlock(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800863 /* leave rtc running, but disable irqs */
Johan Hovold55ba9532014-12-10 15:52:55 -0800864 rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
David Brownelldb68b182006-12-06 20:38:36 -0800865
Keerthy399cf0f2015-08-18 15:11:16 +0530866 if (rtc->has_ext_clk) {
867 reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
868 reg &= ~OMAP_RTC_OSC_SEL_32KCLK_SRC;
869 rtc_write(rtc, OMAP_RTC_OSC_REG, reg);
870 }
871
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700872 rtc->type->lock(rtc);
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -0800873
874 /* Disable the clock/module */
875 pm_runtime_put_sync(&pdev->dev);
876 pm_runtime_disable(&pdev->dev);
877
Marcin Niestroj97ea1902016-09-16 11:26:28 +0200878 /* Remove ext_wakeup pinconf */
879 pinctrl_unregister(rtc->pctldev);
880
David Brownelldb68b182006-12-06 20:38:36 -0800881 return 0;
882}
883
Jingoo Han04ebc352013-04-29 16:21:01 -0700884#ifdef CONFIG_PM_SLEEP
Jingoo Han04ebc352013-04-29 16:21:01 -0700885static int omap_rtc_suspend(struct device *dev)
David Brownelldb68b182006-12-06 20:38:36 -0800886{
Johan Hovold55ba9532014-12-10 15:52:55 -0800887 struct omap_rtc *rtc = dev_get_drvdata(dev);
888
889 rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
David Brownelldb68b182006-12-06 20:38:36 -0800890
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700891 rtc->type->unlock(rtc);
Johan Hovold10211ae2014-12-10 15:53:19 -0800892 /*
893 * FIXME: the RTC alarm is not currently acting as a wakeup event
Hebbar Gururaja8af750e2013-09-11 14:24:18 -0700894 * source on some platforms, and in fact this enable() call is just
895 * saving a flag that's never used...
David Brownelldb68b182006-12-06 20:38:36 -0800896 */
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700897 if (device_may_wakeup(dev))
Johan Hovold55ba9532014-12-10 15:52:55 -0800898 enable_irq_wake(rtc->irq_alarm);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700899 else
Johan Hovold55ba9532014-12-10 15:52:55 -0800900 rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700901 rtc->type->lock(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800902
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -0800903 /* Disable the clock/module */
Jingoo Han04ebc352013-04-29 16:21:01 -0700904 pm_runtime_put_sync(dev);
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -0800905
David Brownelldb68b182006-12-06 20:38:36 -0800906 return 0;
907}
908
Jingoo Han04ebc352013-04-29 16:21:01 -0700909static int omap_rtc_resume(struct device *dev)
David Brownelldb68b182006-12-06 20:38:36 -0800910{
Johan Hovold55ba9532014-12-10 15:52:55 -0800911 struct omap_rtc *rtc = dev_get_drvdata(dev);
912
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -0800913 /* Enable the clock/module so that we can access the registers */
Jingoo Han04ebc352013-04-29 16:21:01 -0700914 pm_runtime_get_sync(dev);
Vaibhav Hiremathfc9bd902012-12-17 16:02:18 -0800915
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700916 rtc->type->unlock(rtc);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700917 if (device_may_wakeup(dev))
Johan Hovold55ba9532014-12-10 15:52:55 -0800918 disable_irq_wake(rtc->irq_alarm);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700919 else
Johan Hovold55ba9532014-12-10 15:52:55 -0800920 rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700921 rtc->type->lock(rtc);
Lokesh Vutlaab7f5802014-06-06 14:36:12 -0700922
David Brownelldb68b182006-12-06 20:38:36 -0800923 return 0;
924}
David Brownelldb68b182006-12-06 20:38:36 -0800925#endif
926
Jingoo Han04ebc352013-04-29 16:21:01 -0700927static SIMPLE_DEV_PM_OPS(omap_rtc_pm_ops, omap_rtc_suspend, omap_rtc_resume);
928
David Brownelldb68b182006-12-06 20:38:36 -0800929static void omap_rtc_shutdown(struct platform_device *pdev)
930{
Johan Hovold55ba9532014-12-10 15:52:55 -0800931 struct omap_rtc *rtc = platform_get_drvdata(pdev);
Johan Hovold8ad5c722014-12-10 15:53:16 -0800932 u8 mask;
Johan Hovold55ba9532014-12-10 15:52:55 -0800933
Johan Hovold8ad5c722014-12-10 15:53:16 -0800934 /*
935 * Keep the ALARM interrupt enabled to allow the system to power up on
936 * alarm events.
937 */
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700938 rtc->type->unlock(rtc);
Johan Hovold8ad5c722014-12-10 15:53:16 -0800939 mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
940 mask &= OMAP_RTC_INTERRUPTS_IT_ALARM;
941 rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask);
Lokesh Vutla9c28bd02015-04-16 12:46:00 -0700942 rtc->type->lock(rtc);
David Brownelldb68b182006-12-06 20:38:36 -0800943}
944
David Brownelldb68b182006-12-06 20:38:36 -0800945static struct platform_driver omap_rtc_driver = {
Lokesh Vutla5d9094b2015-04-16 12:46:05 -0700946 .probe = omap_rtc_probe,
David Brownell71fc8222008-07-23 21:30:38 -0700947 .remove = __exit_p(omap_rtc_remove),
David Brownelldb68b182006-12-06 20:38:36 -0800948 .shutdown = omap_rtc_shutdown,
949 .driver = {
Johan Hovolda430ca22014-12-10 15:52:58 -0800950 .name = "omap_rtc",
Jingoo Han04ebc352013-04-29 16:21:01 -0700951 .pm = &omap_rtc_pm_ops,
Sachin Kamat616b7342013-11-12 15:10:55 -0800952 .of_match_table = omap_rtc_of_match,
David Brownelldb68b182006-12-06 20:38:36 -0800953 },
Johan Hovold2153f942014-12-10 15:53:01 -0800954 .id_table = omap_rtc_id_table,
David Brownelldb68b182006-12-06 20:38:36 -0800955};
956
Lokesh Vutla5d9094b2015-04-16 12:46:05 -0700957module_platform_driver(omap_rtc_driver);
David Brownelldb68b182006-12-06 20:38:36 -0800958
Johan Hovolda430ca22014-12-10 15:52:58 -0800959MODULE_ALIAS("platform:omap_rtc");
David Brownelldb68b182006-12-06 20:38:36 -0800960MODULE_AUTHOR("George G. Davis (and others)");
961MODULE_LICENSE("GPL");