xref: /openbmc/linux/drivers/rtc/rtc-twl.c (revision 8805bace)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2b07682b6SSantosh Shilimkar /*
3ef3b7d0dSBalaji T K  * rtc-twl.c -- TWL Real Time Clock interface
4b07682b6SSantosh Shilimkar  *
5b07682b6SSantosh Shilimkar  * Copyright (C) 2007 MontaVista Software, Inc
6b07682b6SSantosh Shilimkar  * Author: Alexandre Rusev <source@mvista.com>
7b07682b6SSantosh Shilimkar  *
8b07682b6SSantosh Shilimkar  * Based on original TI driver twl4030-rtc.c
9b07682b6SSantosh Shilimkar  *   Copyright (C) 2006 Texas Instruments, Inc.
10b07682b6SSantosh Shilimkar  *
11b07682b6SSantosh Shilimkar  * Based on rtc-omap.c
12b07682b6SSantosh Shilimkar  *   Copyright (C) 2003 MontaVista Software, Inc.
13b07682b6SSantosh Shilimkar  *   Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
14b07682b6SSantosh Shilimkar  *   Copyright (C) 2006 David Brownell
15b07682b6SSantosh Shilimkar  */
16b07682b6SSantosh Shilimkar 
17a737e835SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18a737e835SJoe Perches 
19b07682b6SSantosh Shilimkar #include <linux/kernel.h>
20b07682b6SSantosh Shilimkar #include <linux/errno.h>
21b07682b6SSantosh Shilimkar #include <linux/init.h>
22b07682b6SSantosh Shilimkar #include <linux/module.h>
23b07682b6SSantosh Shilimkar #include <linux/types.h>
24b07682b6SSantosh Shilimkar #include <linux/rtc.h>
25b07682b6SSantosh Shilimkar #include <linux/bcd.h>
26b07682b6SSantosh Shilimkar #include <linux/platform_device.h>
27b07682b6SSantosh Shilimkar #include <linux/interrupt.h>
28c8a6046eSSachin Kamat #include <linux/of.h>
29b07682b6SSantosh Shilimkar 
30a2054256SWolfram Sang #include <linux/mfd/twl.h>
31b07682b6SSantosh Shilimkar 
32e3e7f95bSNicolae Rosia enum twl_class {
33e3e7f95bSNicolae Rosia 	TWL_4030 = 0,
34e3e7f95bSNicolae Rosia 	TWL_6030,
35e3e7f95bSNicolae Rosia };
36b07682b6SSantosh Shilimkar 
37b07682b6SSantosh Shilimkar /*
38b07682b6SSantosh Shilimkar  * RTC block register offsets (use TWL_MODULE_RTC)
39b07682b6SSantosh Shilimkar  */
40a6b49ffdSBalaji T K enum {
41a6b49ffdSBalaji T K 	REG_SECONDS_REG = 0,
42a6b49ffdSBalaji T K 	REG_MINUTES_REG,
43a6b49ffdSBalaji T K 	REG_HOURS_REG,
44a6b49ffdSBalaji T K 	REG_DAYS_REG,
45a6b49ffdSBalaji T K 	REG_MONTHS_REG,
46a6b49ffdSBalaji T K 	REG_YEARS_REG,
47a6b49ffdSBalaji T K 	REG_WEEKS_REG,
48b07682b6SSantosh Shilimkar 
49a6b49ffdSBalaji T K 	REG_ALARM_SECONDS_REG,
50a6b49ffdSBalaji T K 	REG_ALARM_MINUTES_REG,
51a6b49ffdSBalaji T K 	REG_ALARM_HOURS_REG,
52a6b49ffdSBalaji T K 	REG_ALARM_DAYS_REG,
53a6b49ffdSBalaji T K 	REG_ALARM_MONTHS_REG,
54a6b49ffdSBalaji T K 	REG_ALARM_YEARS_REG,
55b07682b6SSantosh Shilimkar 
56a6b49ffdSBalaji T K 	REG_RTC_CTRL_REG,
57a6b49ffdSBalaji T K 	REG_RTC_STATUS_REG,
58a6b49ffdSBalaji T K 	REG_RTC_INTERRUPTS_REG,
59b07682b6SSantosh Shilimkar 
60a6b49ffdSBalaji T K 	REG_RTC_COMP_LSB_REG,
61a6b49ffdSBalaji T K 	REG_RTC_COMP_MSB_REG,
62a6b49ffdSBalaji T K };
632e84067bSTobias Klauser static const u8 twl4030_rtc_reg_map[] = {
64a6b49ffdSBalaji T K 	[REG_SECONDS_REG] = 0x00,
65a6b49ffdSBalaji T K 	[REG_MINUTES_REG] = 0x01,
66a6b49ffdSBalaji T K 	[REG_HOURS_REG] = 0x02,
67a6b49ffdSBalaji T K 	[REG_DAYS_REG] = 0x03,
68a6b49ffdSBalaji T K 	[REG_MONTHS_REG] = 0x04,
69a6b49ffdSBalaji T K 	[REG_YEARS_REG] = 0x05,
70a6b49ffdSBalaji T K 	[REG_WEEKS_REG] = 0x06,
71a6b49ffdSBalaji T K 
72a6b49ffdSBalaji T K 	[REG_ALARM_SECONDS_REG] = 0x07,
73a6b49ffdSBalaji T K 	[REG_ALARM_MINUTES_REG] = 0x08,
74a6b49ffdSBalaji T K 	[REG_ALARM_HOURS_REG] = 0x09,
75a6b49ffdSBalaji T K 	[REG_ALARM_DAYS_REG] = 0x0A,
76a6b49ffdSBalaji T K 	[REG_ALARM_MONTHS_REG] = 0x0B,
77a6b49ffdSBalaji T K 	[REG_ALARM_YEARS_REG] = 0x0C,
78a6b49ffdSBalaji T K 
79a6b49ffdSBalaji T K 	[REG_RTC_CTRL_REG] = 0x0D,
80a6b49ffdSBalaji T K 	[REG_RTC_STATUS_REG] = 0x0E,
81a6b49ffdSBalaji T K 	[REG_RTC_INTERRUPTS_REG] = 0x0F,
82a6b49ffdSBalaji T K 
83a6b49ffdSBalaji T K 	[REG_RTC_COMP_LSB_REG] = 0x10,
84a6b49ffdSBalaji T K 	[REG_RTC_COMP_MSB_REG] = 0x11,
85a6b49ffdSBalaji T K };
862e84067bSTobias Klauser static const u8 twl6030_rtc_reg_map[] = {
87a6b49ffdSBalaji T K 	[REG_SECONDS_REG] = 0x00,
88a6b49ffdSBalaji T K 	[REG_MINUTES_REG] = 0x01,
89a6b49ffdSBalaji T K 	[REG_HOURS_REG] = 0x02,
90a6b49ffdSBalaji T K 	[REG_DAYS_REG] = 0x03,
91a6b49ffdSBalaji T K 	[REG_MONTHS_REG] = 0x04,
92a6b49ffdSBalaji T K 	[REG_YEARS_REG] = 0x05,
93a6b49ffdSBalaji T K 	[REG_WEEKS_REG] = 0x06,
94a6b49ffdSBalaji T K 
95a6b49ffdSBalaji T K 	[REG_ALARM_SECONDS_REG] = 0x08,
96a6b49ffdSBalaji T K 	[REG_ALARM_MINUTES_REG] = 0x09,
97a6b49ffdSBalaji T K 	[REG_ALARM_HOURS_REG] = 0x0A,
98a6b49ffdSBalaji T K 	[REG_ALARM_DAYS_REG] = 0x0B,
99a6b49ffdSBalaji T K 	[REG_ALARM_MONTHS_REG] = 0x0C,
100a6b49ffdSBalaji T K 	[REG_ALARM_YEARS_REG] = 0x0D,
101a6b49ffdSBalaji T K 
102a6b49ffdSBalaji T K 	[REG_RTC_CTRL_REG] = 0x10,
103a6b49ffdSBalaji T K 	[REG_RTC_STATUS_REG] = 0x11,
104a6b49ffdSBalaji T K 	[REG_RTC_INTERRUPTS_REG] = 0x12,
105a6b49ffdSBalaji T K 
106a6b49ffdSBalaji T K 	[REG_RTC_COMP_LSB_REG] = 0x13,
107a6b49ffdSBalaji T K 	[REG_RTC_COMP_MSB_REG] = 0x14,
108a6b49ffdSBalaji T K };
109b07682b6SSantosh Shilimkar 
110b07682b6SSantosh Shilimkar /* RTC_CTRL_REG bitfields */
111b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_STOP_RTC_M              0x01
112b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_ROUND_30S_M             0x02
113b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_AUTO_COMP_M             0x04
114b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_MODE_12_24_M            0x08
115b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_TEST_MODE_M             0x10
116b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M        0x20
117b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_GET_TIME_M              0x40
118f3ec434cSKonstantin Shlyakhovoy #define BIT_RTC_CTRL_REG_RTC_V_OPT               0x80
119b07682b6SSantosh Shilimkar 
120b07682b6SSantosh Shilimkar /* RTC_STATUS_REG bitfields */
121b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_RUN_M                 0x02
122b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1S_EVENT_M            0x04
123b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1M_EVENT_M            0x08
124b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1H_EVENT_M            0x10
125b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1D_EVENT_M            0x20
126b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_ALARM_M               0x40
127b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_POWER_UP_M            0x80
128b07682b6SSantosh Shilimkar 
129b07682b6SSantosh Shilimkar /* RTC_INTERRUPTS_REG bitfields */
130b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_EVERY_M           0x03
131b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M        0x04
132b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M        0x08
133b07682b6SSantosh Shilimkar 
134b07682b6SSantosh Shilimkar 
135b07682b6SSantosh Shilimkar /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
136b07682b6SSantosh Shilimkar #define ALL_TIME_REGS		6
137b07682b6SSantosh Shilimkar 
138b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/
139e3e7f95bSNicolae Rosia struct twl_rtc {
140e3e7f95bSNicolae Rosia 	struct device *dev;
141e3e7f95bSNicolae Rosia 	struct rtc_device *rtc;
142e3e7f95bSNicolae Rosia 	u8 *reg_map;
143e3e7f95bSNicolae Rosia 	/*
144e3e7f95bSNicolae Rosia 	 * Cache the value for timer/alarm interrupts register; this is
145e3e7f95bSNicolae Rosia 	 * only changed by callers holding rtc ops lock (or resume).
146e3e7f95bSNicolae Rosia 	 */
147e3e7f95bSNicolae Rosia 	unsigned char rtc_irq_bits;
148e3e7f95bSNicolae Rosia 	bool wake_enabled;
149e3e7f95bSNicolae Rosia #ifdef CONFIG_PM_SLEEP
150e3e7f95bSNicolae Rosia 	unsigned char irqstat;
151e3e7f95bSNicolae Rosia #endif
152e3e7f95bSNicolae Rosia 	enum twl_class class;
153e3e7f95bSNicolae Rosia };
154b07682b6SSantosh Shilimkar 
155b07682b6SSantosh Shilimkar /*
156ef3b7d0dSBalaji T K  * Supports 1 byte read from TWL RTC register.
157b07682b6SSantosh Shilimkar  */
twl_rtc_read_u8(struct twl_rtc * twl_rtc,u8 * data,u8 reg)158e3e7f95bSNicolae Rosia static int twl_rtc_read_u8(struct twl_rtc *twl_rtc, u8 *data, u8 reg)
159b07682b6SSantosh Shilimkar {
160b07682b6SSantosh Shilimkar 	int ret;
161b07682b6SSantosh Shilimkar 
162e3e7f95bSNicolae Rosia 	ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
163b07682b6SSantosh Shilimkar 	if (ret < 0)
164a737e835SJoe Perches 		pr_err("Could not read TWL register %X - error %d\n", reg, ret);
165b07682b6SSantosh Shilimkar 	return ret;
166b07682b6SSantosh Shilimkar }
167b07682b6SSantosh Shilimkar 
168b07682b6SSantosh Shilimkar /*
169ef3b7d0dSBalaji T K  * Supports 1 byte write to TWL RTC registers.
170b07682b6SSantosh Shilimkar  */
twl_rtc_write_u8(struct twl_rtc * twl_rtc,u8 data,u8 reg)171e3e7f95bSNicolae Rosia static int twl_rtc_write_u8(struct twl_rtc *twl_rtc, u8 data, u8 reg)
172b07682b6SSantosh Shilimkar {
173b07682b6SSantosh Shilimkar 	int ret;
174b07682b6SSantosh Shilimkar 
175e3e7f95bSNicolae Rosia 	ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
176b07682b6SSantosh Shilimkar 	if (ret < 0)
177a737e835SJoe Perches 		pr_err("Could not write TWL register %X - error %d\n",
178a737e835SJoe Perches 		       reg, ret);
179b07682b6SSantosh Shilimkar 	return ret;
180b07682b6SSantosh Shilimkar }
181b07682b6SSantosh Shilimkar 
182b07682b6SSantosh Shilimkar /*
183b07682b6SSantosh Shilimkar  * Enable 1/second update and/or alarm interrupts.
184b07682b6SSantosh Shilimkar  */
set_rtc_irq_bit(struct twl_rtc * twl_rtc,unsigned char bit)185e3e7f95bSNicolae Rosia static int set_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
186b07682b6SSantosh Shilimkar {
187b07682b6SSantosh Shilimkar 	unsigned char val;
188b07682b6SSantosh Shilimkar 	int ret;
189b07682b6SSantosh Shilimkar 
190ce9f6506SVenu Byravarasu 	/* if the bit is set, return from here */
191e3e7f95bSNicolae Rosia 	if (twl_rtc->rtc_irq_bits & bit)
192ce9f6506SVenu Byravarasu 		return 0;
193ce9f6506SVenu Byravarasu 
194e3e7f95bSNicolae Rosia 	val = twl_rtc->rtc_irq_bits | bit;
195b07682b6SSantosh Shilimkar 	val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
196e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
197b07682b6SSantosh Shilimkar 	if (ret == 0)
198e3e7f95bSNicolae Rosia 		twl_rtc->rtc_irq_bits = val;
199b07682b6SSantosh Shilimkar 
200b07682b6SSantosh Shilimkar 	return ret;
201b07682b6SSantosh Shilimkar }
202b07682b6SSantosh Shilimkar 
203b07682b6SSantosh Shilimkar /*
204b07682b6SSantosh Shilimkar  * Disable update and/or alarm interrupts.
205b07682b6SSantosh Shilimkar  */
mask_rtc_irq_bit(struct twl_rtc * twl_rtc,unsigned char bit)206e3e7f95bSNicolae Rosia static int mask_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
207b07682b6SSantosh Shilimkar {
208b07682b6SSantosh Shilimkar 	unsigned char val;
209b07682b6SSantosh Shilimkar 	int ret;
210b07682b6SSantosh Shilimkar 
211ce9f6506SVenu Byravarasu 	/* if the bit is clear, return from here */
212e3e7f95bSNicolae Rosia 	if (!(twl_rtc->rtc_irq_bits & bit))
213ce9f6506SVenu Byravarasu 		return 0;
214ce9f6506SVenu Byravarasu 
215e3e7f95bSNicolae Rosia 	val = twl_rtc->rtc_irq_bits & ~bit;
216e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
217b07682b6SSantosh Shilimkar 	if (ret == 0)
218e3e7f95bSNicolae Rosia 		twl_rtc->rtc_irq_bits = val;
219b07682b6SSantosh Shilimkar 
220b07682b6SSantosh Shilimkar 	return ret;
221b07682b6SSantosh Shilimkar }
222b07682b6SSantosh Shilimkar 
twl_rtc_alarm_irq_enable(struct device * dev,unsigned enabled)223ef3b7d0dSBalaji T K static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
224b07682b6SSantosh Shilimkar {
225ae845894SKevin Hilman 	struct platform_device *pdev = to_platform_device(dev);
226e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
227ae845894SKevin Hilman 	int irq = platform_get_irq(pdev, 0);
228b07682b6SSantosh Shilimkar 	int ret;
229b07682b6SSantosh Shilimkar 
230ae845894SKevin Hilman 	if (enabled) {
231e3e7f95bSNicolae Rosia 		ret = set_rtc_irq_bit(twl_rtc,
232e3e7f95bSNicolae Rosia 				      BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
233e3e7f95bSNicolae Rosia 		if (device_can_wakeup(dev) && !twl_rtc->wake_enabled) {
234ae845894SKevin Hilman 			enable_irq_wake(irq);
235e3e7f95bSNicolae Rosia 			twl_rtc->wake_enabled = true;
236ae845894SKevin Hilman 		}
237ae845894SKevin Hilman 	} else {
238e3e7f95bSNicolae Rosia 		ret = mask_rtc_irq_bit(twl_rtc,
239e3e7f95bSNicolae Rosia 				       BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
240e3e7f95bSNicolae Rosia 		if (twl_rtc->wake_enabled) {
241ae845894SKevin Hilman 			disable_irq_wake(irq);
242e3e7f95bSNicolae Rosia 			twl_rtc->wake_enabled = false;
243ae845894SKevin Hilman 		}
244ae845894SKevin Hilman 	}
245b07682b6SSantosh Shilimkar 
246b07682b6SSantosh Shilimkar 	return ret;
247b07682b6SSantosh Shilimkar }
248b07682b6SSantosh Shilimkar 
249b07682b6SSantosh Shilimkar /*
250ef3b7d0dSBalaji T K  * Gets current TWL RTC time and date parameters.
251b07682b6SSantosh Shilimkar  *
252b07682b6SSantosh Shilimkar  * The RTC's time/alarm representation is not what gmtime(3) requires
253b07682b6SSantosh Shilimkar  * Linux to use:
254b07682b6SSantosh Shilimkar  *
255b07682b6SSantosh Shilimkar  *  - Months are 1..12 vs Linux 0-11
256b07682b6SSantosh Shilimkar  *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
257b07682b6SSantosh Shilimkar  */
twl_rtc_read_time(struct device * dev,struct rtc_time * tm)258ef3b7d0dSBalaji T K static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
259b07682b6SSantosh Shilimkar {
260e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
26114591d88SPeter Ujfalusi 	unsigned char rtc_data[ALL_TIME_REGS];
262b07682b6SSantosh Shilimkar 	int ret;
263b07682b6SSantosh Shilimkar 	u8 save_control;
264f3ec434cSKonstantin Shlyakhovoy 	u8 rtc_control;
265b07682b6SSantosh Shilimkar 
266e3e7f95bSNicolae Rosia 	ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
267f3ec434cSKonstantin Shlyakhovoy 	if (ret < 0) {
268f3ec434cSKonstantin Shlyakhovoy 		dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret);
269b07682b6SSantosh Shilimkar 		return ret;
270f3ec434cSKonstantin Shlyakhovoy 	}
271f3ec434cSKonstantin Shlyakhovoy 	/* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */
272e3e7f95bSNicolae Rosia 	if (twl_rtc->class == TWL_6030) {
273f3ec434cSKonstantin Shlyakhovoy 		if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) {
274f3ec434cSKonstantin Shlyakhovoy 			save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M;
275e3e7f95bSNicolae Rosia 			ret = twl_rtc_write_u8(twl_rtc, save_control,
276e3e7f95bSNicolae Rosia 					       REG_RTC_CTRL_REG);
277f3ec434cSKonstantin Shlyakhovoy 			if (ret < 0) {
278f3ec434cSKonstantin Shlyakhovoy 				dev_err(dev, "%s clr GET_TIME, error %d\n",
279f3ec434cSKonstantin Shlyakhovoy 					__func__, ret);
280b07682b6SSantosh Shilimkar 				return ret;
281f3ec434cSKonstantin Shlyakhovoy 			}
282f3ec434cSKonstantin Shlyakhovoy 		}
283f3ec434cSKonstantin Shlyakhovoy 	}
284f3ec434cSKonstantin Shlyakhovoy 
285f3ec434cSKonstantin Shlyakhovoy 	/* Copy RTC counting registers to static registers or latches */
286f3ec434cSKonstantin Shlyakhovoy 	rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M;
287f3ec434cSKonstantin Shlyakhovoy 
288f3ec434cSKonstantin Shlyakhovoy 	/* for twl6030/32 enable read access to static shadowed registers */
289e3e7f95bSNicolae Rosia 	if (twl_rtc->class == TWL_6030)
290f3ec434cSKonstantin Shlyakhovoy 		rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT;
291f3ec434cSKonstantin Shlyakhovoy 
292e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, rtc_control, REG_RTC_CTRL_REG);
293f3ec434cSKonstantin Shlyakhovoy 	if (ret < 0) {
294f3ec434cSKonstantin Shlyakhovoy 		dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret);
295f3ec434cSKonstantin Shlyakhovoy 		return ret;
296f3ec434cSKonstantin Shlyakhovoy 	}
297b07682b6SSantosh Shilimkar 
298ef3b7d0dSBalaji T K 	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
299e3e7f95bSNicolae Rosia 			(twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
300b07682b6SSantosh Shilimkar 
301b07682b6SSantosh Shilimkar 	if (ret < 0) {
302f3ec434cSKonstantin Shlyakhovoy 		dev_err(dev, "%s: reading data, error %d\n", __func__, ret);
303b07682b6SSantosh Shilimkar 		return ret;
304b07682b6SSantosh Shilimkar 	}
305b07682b6SSantosh Shilimkar 
306f3ec434cSKonstantin Shlyakhovoy 	/* for twl6030 restore original state of rtc control register */
307e3e7f95bSNicolae Rosia 	if (twl_rtc->class == TWL_6030) {
308e3e7f95bSNicolae Rosia 		ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
309f3ec434cSKonstantin Shlyakhovoy 		if (ret < 0) {
310f3ec434cSKonstantin Shlyakhovoy 			dev_err(dev, "%s: restore CTRL_REG, error %d\n",
311f3ec434cSKonstantin Shlyakhovoy 				__func__, ret);
312f3ec434cSKonstantin Shlyakhovoy 			return ret;
313f3ec434cSKonstantin Shlyakhovoy 		}
314f3ec434cSKonstantin Shlyakhovoy 	}
315f3ec434cSKonstantin Shlyakhovoy 
316b07682b6SSantosh Shilimkar 	tm->tm_sec = bcd2bin(rtc_data[0]);
317b07682b6SSantosh Shilimkar 	tm->tm_min = bcd2bin(rtc_data[1]);
318b07682b6SSantosh Shilimkar 	tm->tm_hour = bcd2bin(rtc_data[2]);
319b07682b6SSantosh Shilimkar 	tm->tm_mday = bcd2bin(rtc_data[3]);
320b07682b6SSantosh Shilimkar 	tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
321b07682b6SSantosh Shilimkar 	tm->tm_year = bcd2bin(rtc_data[5]) + 100;
322b07682b6SSantosh Shilimkar 
323b07682b6SSantosh Shilimkar 	return ret;
324b07682b6SSantosh Shilimkar }
325b07682b6SSantosh Shilimkar 
twl_rtc_set_time(struct device * dev,struct rtc_time * tm)326ef3b7d0dSBalaji T K static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
327b07682b6SSantosh Shilimkar {
328e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
329b07682b6SSantosh Shilimkar 	unsigned char save_control;
33014591d88SPeter Ujfalusi 	unsigned char rtc_data[ALL_TIME_REGS];
331b07682b6SSantosh Shilimkar 	int ret;
332b07682b6SSantosh Shilimkar 
33314591d88SPeter Ujfalusi 	rtc_data[0] = bin2bcd(tm->tm_sec);
33414591d88SPeter Ujfalusi 	rtc_data[1] = bin2bcd(tm->tm_min);
33514591d88SPeter Ujfalusi 	rtc_data[2] = bin2bcd(tm->tm_hour);
33614591d88SPeter Ujfalusi 	rtc_data[3] = bin2bcd(tm->tm_mday);
33714591d88SPeter Ujfalusi 	rtc_data[4] = bin2bcd(tm->tm_mon + 1);
33814591d88SPeter Ujfalusi 	rtc_data[5] = bin2bcd(tm->tm_year - 100);
339b07682b6SSantosh Shilimkar 
340b07682b6SSantosh Shilimkar 	/* Stop RTC while updating the TC registers */
341e3e7f95bSNicolae Rosia 	ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
342b07682b6SSantosh Shilimkar 	if (ret < 0)
343b07682b6SSantosh Shilimkar 		goto out;
344b07682b6SSantosh Shilimkar 
345b07682b6SSantosh Shilimkar 	save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
346e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
347b07682b6SSantosh Shilimkar 	if (ret < 0)
348b07682b6SSantosh Shilimkar 		goto out;
349b07682b6SSantosh Shilimkar 
350b07682b6SSantosh Shilimkar 	/* update all the time registers in one shot */
351ef3b7d0dSBalaji T K 	ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
352e3e7f95bSNicolae Rosia 		(twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
353b07682b6SSantosh Shilimkar 	if (ret < 0) {
354b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_set_time error %d\n", ret);
355b07682b6SSantosh Shilimkar 		goto out;
356b07682b6SSantosh Shilimkar 	}
357b07682b6SSantosh Shilimkar 
358b07682b6SSantosh Shilimkar 	/* Start back RTC */
359b07682b6SSantosh Shilimkar 	save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
360e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
361b07682b6SSantosh Shilimkar 
362b07682b6SSantosh Shilimkar out:
363b07682b6SSantosh Shilimkar 	return ret;
364b07682b6SSantosh Shilimkar }
365b07682b6SSantosh Shilimkar 
366b07682b6SSantosh Shilimkar /*
367ef3b7d0dSBalaji T K  * Gets current TWL RTC alarm time.
368b07682b6SSantosh Shilimkar  */
twl_rtc_read_alarm(struct device * dev,struct rtc_wkalrm * alm)369ef3b7d0dSBalaji T K static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
370b07682b6SSantosh Shilimkar {
371e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
37214591d88SPeter Ujfalusi 	unsigned char rtc_data[ALL_TIME_REGS];
373b07682b6SSantosh Shilimkar 	int ret;
374b07682b6SSantosh Shilimkar 
375ef3b7d0dSBalaji T K 	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
376e3e7f95bSNicolae Rosia 			twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
377b07682b6SSantosh Shilimkar 	if (ret < 0) {
378b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_read_alarm error %d\n", ret);
379b07682b6SSantosh Shilimkar 		return ret;
380b07682b6SSantosh Shilimkar 	}
381b07682b6SSantosh Shilimkar 
382b07682b6SSantosh Shilimkar 	/* some of these fields may be wildcard/"match all" */
383b07682b6SSantosh Shilimkar 	alm->time.tm_sec = bcd2bin(rtc_data[0]);
384b07682b6SSantosh Shilimkar 	alm->time.tm_min = bcd2bin(rtc_data[1]);
385b07682b6SSantosh Shilimkar 	alm->time.tm_hour = bcd2bin(rtc_data[2]);
386b07682b6SSantosh Shilimkar 	alm->time.tm_mday = bcd2bin(rtc_data[3]);
387b07682b6SSantosh Shilimkar 	alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
388b07682b6SSantosh Shilimkar 	alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
389b07682b6SSantosh Shilimkar 
390b07682b6SSantosh Shilimkar 	/* report cached alarm enable state */
391e3e7f95bSNicolae Rosia 	if (twl_rtc->rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
392b07682b6SSantosh Shilimkar 		alm->enabled = 1;
393b07682b6SSantosh Shilimkar 
394b07682b6SSantosh Shilimkar 	return ret;
395b07682b6SSantosh Shilimkar }
396b07682b6SSantosh Shilimkar 
twl_rtc_set_alarm(struct device * dev,struct rtc_wkalrm * alm)397ef3b7d0dSBalaji T K static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
398b07682b6SSantosh Shilimkar {
399e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
400e3e7f95bSNicolae Rosia 
40114591d88SPeter Ujfalusi 	unsigned char alarm_data[ALL_TIME_REGS];
402b07682b6SSantosh Shilimkar 	int ret;
403b07682b6SSantosh Shilimkar 
404ef3b7d0dSBalaji T K 	ret = twl_rtc_alarm_irq_enable(dev, 0);
405b07682b6SSantosh Shilimkar 	if (ret)
406b07682b6SSantosh Shilimkar 		goto out;
407b07682b6SSantosh Shilimkar 
40814591d88SPeter Ujfalusi 	alarm_data[0] = bin2bcd(alm->time.tm_sec);
40914591d88SPeter Ujfalusi 	alarm_data[1] = bin2bcd(alm->time.tm_min);
41014591d88SPeter Ujfalusi 	alarm_data[2] = bin2bcd(alm->time.tm_hour);
41114591d88SPeter Ujfalusi 	alarm_data[3] = bin2bcd(alm->time.tm_mday);
41214591d88SPeter Ujfalusi 	alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
41314591d88SPeter Ujfalusi 	alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
414b07682b6SSantosh Shilimkar 
415b07682b6SSantosh Shilimkar 	/* update all the alarm registers in one shot */
416ef3b7d0dSBalaji T K 	ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
417e3e7f95bSNicolae Rosia 			twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
418b07682b6SSantosh Shilimkar 	if (ret) {
419b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_set_alarm error %d\n", ret);
420b07682b6SSantosh Shilimkar 		goto out;
421b07682b6SSantosh Shilimkar 	}
422b07682b6SSantosh Shilimkar 
423b07682b6SSantosh Shilimkar 	if (alm->enabled)
424ef3b7d0dSBalaji T K 		ret = twl_rtc_alarm_irq_enable(dev, 1);
425b07682b6SSantosh Shilimkar out:
426b07682b6SSantosh Shilimkar 	return ret;
427b07682b6SSantosh Shilimkar }
428b07682b6SSantosh Shilimkar 
twl_rtc_interrupt(int irq,void * data)429e3e7f95bSNicolae Rosia static irqreturn_t twl_rtc_interrupt(int irq, void *data)
430b07682b6SSantosh Shilimkar {
431e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = data;
4322778ebccSVenu Byravarasu 	unsigned long events;
433b07682b6SSantosh Shilimkar 	int ret = IRQ_NONE;
434b07682b6SSantosh Shilimkar 	int res;
435b07682b6SSantosh Shilimkar 	u8 rd_reg;
436b07682b6SSantosh Shilimkar 
437e3e7f95bSNicolae Rosia 	res = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
438b07682b6SSantosh Shilimkar 	if (res)
439b07682b6SSantosh Shilimkar 		goto out;
440b07682b6SSantosh Shilimkar 	/*
441b07682b6SSantosh Shilimkar 	 * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
442b07682b6SSantosh Shilimkar 	 * only one (ALARM or RTC) interrupt source may be enabled
443b07682b6SSantosh Shilimkar 	 * at time, we also could check our results
444b07682b6SSantosh Shilimkar 	 * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
445b07682b6SSantosh Shilimkar 	 */
446b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
4472778ebccSVenu Byravarasu 		events = RTC_IRQF | RTC_AF;
448b07682b6SSantosh Shilimkar 	else
4492778ebccSVenu Byravarasu 		events = RTC_IRQF | RTC_PF;
450b07682b6SSantosh Shilimkar 
451e3e7f95bSNicolae Rosia 	res = twl_rtc_write_u8(twl_rtc, BIT_RTC_STATUS_REG_ALARM_M,
452b07682b6SSantosh Shilimkar 			       REG_RTC_STATUS_REG);
453b07682b6SSantosh Shilimkar 	if (res)
454b07682b6SSantosh Shilimkar 		goto out;
455b07682b6SSantosh Shilimkar 
456e3e7f95bSNicolae Rosia 	if (twl_rtc->class == TWL_4030) {
457b07682b6SSantosh Shilimkar 		/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
458b07682b6SSantosh Shilimkar 		 * needs 2 reads to clear the interrupt. One read is done in
459ef3b7d0dSBalaji T K 		 * do_twl_pwrirq(). Doing the second read, to clear
460b07682b6SSantosh Shilimkar 		 * the bit.
461b07682b6SSantosh Shilimkar 		 *
462b07682b6SSantosh Shilimkar 		 * FIXME the reason PWR_ISR1 needs an extra read is that
463b07682b6SSantosh Shilimkar 		 * RTC_IF retriggered until we cleared REG_ALARM_M above.
464b07682b6SSantosh Shilimkar 		 * But re-reading like this is a bad hack; by doing so we
465b07682b6SSantosh Shilimkar 		 * risk wrongly clearing status for some other IRQ (losing
466b07682b6SSantosh Shilimkar 		 * the interrupt).  Be smarter about handling RTC_UF ...
467b07682b6SSantosh Shilimkar 		 */
468fc7b92fcSBalaji T K 		res = twl_i2c_read_u8(TWL4030_MODULE_INT,
469b07682b6SSantosh Shilimkar 			&rd_reg, TWL4030_INT_PWR_ISR1);
470b07682b6SSantosh Shilimkar 		if (res)
471b07682b6SSantosh Shilimkar 			goto out;
472a6b49ffdSBalaji T K 	}
473b07682b6SSantosh Shilimkar 
474b07682b6SSantosh Shilimkar 	/* Notify RTC core on event */
475e3e7f95bSNicolae Rosia 	rtc_update_irq(twl_rtc->rtc, 1, events);
476b07682b6SSantosh Shilimkar 
477b07682b6SSantosh Shilimkar 	ret = IRQ_HANDLED;
478b07682b6SSantosh Shilimkar out:
479b07682b6SSantosh Shilimkar 	return ret;
480b07682b6SSantosh Shilimkar }
481b07682b6SSantosh Shilimkar 
48234c7b3acSJulia Lawall static const struct rtc_class_ops twl_rtc_ops = {
483ef3b7d0dSBalaji T K 	.read_time	= twl_rtc_read_time,
484ef3b7d0dSBalaji T K 	.set_time	= twl_rtc_set_time,
485ef3b7d0dSBalaji T K 	.read_alarm	= twl_rtc_read_alarm,
486ef3b7d0dSBalaji T K 	.set_alarm	= twl_rtc_set_alarm,
487ef3b7d0dSBalaji T K 	.alarm_irq_enable = twl_rtc_alarm_irq_enable,
488b07682b6SSantosh Shilimkar };
489b07682b6SSantosh Shilimkar 
twl_nvram_read(void * priv,unsigned int offset,void * val,size_t bytes)4907130856fSLadislav Michl static int twl_nvram_read(void *priv, unsigned int offset, void *val,
4917130856fSLadislav Michl 			  size_t bytes)
4927130856fSLadislav Michl {
4937130856fSLadislav Michl 	return twl_i2c_read((long)priv, val, offset, bytes);
4947130856fSLadislav Michl }
4957130856fSLadislav Michl 
twl_nvram_write(void * priv,unsigned int offset,void * val,size_t bytes)4967130856fSLadislav Michl static int twl_nvram_write(void *priv, unsigned int offset, void *val,
4977130856fSLadislav Michl 			   size_t bytes)
4987130856fSLadislav Michl {
4997130856fSLadislav Michl 	return twl_i2c_write((long)priv, val, offset, bytes);
5007130856fSLadislav Michl }
5017130856fSLadislav Michl 
502b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/
503b07682b6SSantosh Shilimkar 
twl_rtc_probe(struct platform_device * pdev)5045a167f45SGreg Kroah-Hartman static int twl_rtc_probe(struct platform_device *pdev)
505b07682b6SSantosh Shilimkar {
506e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc;
5077130856fSLadislav Michl 	struct nvmem_config nvmem_cfg;
5081c02cbfeSNicolae Rosia 	struct device_node *np = pdev->dev.of_node;
5097e72c686STodd Poynor 	int ret = -EINVAL;
510b07682b6SSantosh Shilimkar 	int irq = platform_get_irq(pdev, 0);
511b07682b6SSantosh Shilimkar 	u8 rd_reg;
512b07682b6SSantosh Shilimkar 
5131c02cbfeSNicolae Rosia 	if (!np) {
5141c02cbfeSNicolae Rosia 		dev_err(&pdev->dev, "no DT info\n");
5151c02cbfeSNicolae Rosia 		return -EINVAL;
5161c02cbfeSNicolae Rosia 	}
5171c02cbfeSNicolae Rosia 
518b07682b6SSantosh Shilimkar 	if (irq <= 0)
519f53eeb85SJingoo Han 		return ret;
520b07682b6SSantosh Shilimkar 
521e3e7f95bSNicolae Rosia 	twl_rtc = devm_kzalloc(&pdev->dev, sizeof(*twl_rtc), GFP_KERNEL);
522e3e7f95bSNicolae Rosia 	if (!twl_rtc)
523e3e7f95bSNicolae Rosia 		return -ENOMEM;
524d3869ff6SPeter Ujfalusi 
525e3e7f95bSNicolae Rosia 	if (twl_class_is_4030()) {
526e3e7f95bSNicolae Rosia 		twl_rtc->class = TWL_4030;
527e3e7f95bSNicolae Rosia 		twl_rtc->reg_map = (u8 *)twl4030_rtc_reg_map;
528e3e7f95bSNicolae Rosia 	} else if (twl_class_is_6030()) {
529e3e7f95bSNicolae Rosia 		twl_rtc->class = TWL_6030;
530e3e7f95bSNicolae Rosia 		twl_rtc->reg_map = (u8 *)twl6030_rtc_reg_map;
531e3e7f95bSNicolae Rosia 	} else {
532e3e7f95bSNicolae Rosia 		dev_err(&pdev->dev, "TWL Class not supported.\n");
533e3e7f95bSNicolae Rosia 		return -EINVAL;
534e3e7f95bSNicolae Rosia 	}
535e3e7f95bSNicolae Rosia 
536e3e7f95bSNicolae Rosia 	ret = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
537b07682b6SSantosh Shilimkar 	if (ret < 0)
538f53eeb85SJingoo Han 		return ret;
539b07682b6SSantosh Shilimkar 
540b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
541b07682b6SSantosh Shilimkar 		dev_warn(&pdev->dev, "Power up reset detected.\n");
542b07682b6SSantosh Shilimkar 
543b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
544b07682b6SSantosh Shilimkar 		dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
545b07682b6SSantosh Shilimkar 
546b07682b6SSantosh Shilimkar 	/* Clear RTC Power up reset and pending alarm interrupts */
547e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, rd_reg, REG_RTC_STATUS_REG);
548b07682b6SSantosh Shilimkar 	if (ret < 0)
549f53eeb85SJingoo Han 		return ret;
550b07682b6SSantosh Shilimkar 
551e3e7f95bSNicolae Rosia 	if (twl_rtc->class == TWL_6030) {
552a6b49ffdSBalaji T K 		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
553a6b49ffdSBalaji T K 			REG_INT_MSK_LINE_A);
554a6b49ffdSBalaji T K 		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
555a6b49ffdSBalaji T K 			REG_INT_MSK_STS_A);
556a6b49ffdSBalaji T K 	}
557a6b49ffdSBalaji T K 
558e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
559e3e7f95bSNicolae Rosia 			       REG_RTC_CTRL_REG);
560b07682b6SSantosh Shilimkar 	if (ret < 0)
561f53eeb85SJingoo Han 		return ret;
562b07682b6SSantosh Shilimkar 
5638dcebaa9SKevin Hilman 	/* ensure interrupts are disabled, bootloaders can be strange */
564e3e7f95bSNicolae Rosia 	ret = twl_rtc_write_u8(twl_rtc, 0, REG_RTC_INTERRUPTS_REG);
5658dcebaa9SKevin Hilman 	if (ret < 0)
5668dcebaa9SKevin Hilman 		dev_warn(&pdev->dev, "unable to disable interrupt\n");
5678dcebaa9SKevin Hilman 
568b07682b6SSantosh Shilimkar 	/* init cached IRQ enable bits */
569e3e7f95bSNicolae Rosia 	ret = twl_rtc_read_u8(twl_rtc, &twl_rtc->rtc_irq_bits,
570e3e7f95bSNicolae Rosia 			      REG_RTC_INTERRUPTS_REG);
571b07682b6SSantosh Shilimkar 	if (ret < 0)
572f53eeb85SJingoo Han 		return ret;
573b07682b6SSantosh Shilimkar 
574e3e7f95bSNicolae Rosia 	platform_set_drvdata(pdev, twl_rtc);
575b99b94b5SGrygorii Strashko 	device_init_wakeup(&pdev->dev, 1);
576b99b94b5SGrygorii Strashko 
577e3e7f95bSNicolae Rosia 	twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
578f53eeb85SJingoo Han 					&twl_rtc_ops, THIS_MODULE);
579*8805baceSAlexandre Belloni 	if (IS_ERR(twl_rtc->rtc))
580e3e7f95bSNicolae Rosia 		return PTR_ERR(twl_rtc->rtc);
5817e72c686STodd Poynor 
582f53eeb85SJingoo Han 	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
583f53eeb85SJingoo Han 					twl_rtc_interrupt,
5846b91bf1aSKevin Hilman 					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
585e3e7f95bSNicolae Rosia 					dev_name(&twl_rtc->rtc->dev), twl_rtc);
5867e72c686STodd Poynor 	if (ret < 0) {
5877e72c686STodd Poynor 		dev_err(&pdev->dev, "IRQ is not free.\n");
588f53eeb85SJingoo Han 		return ret;
5897e72c686STodd Poynor 	}
5907e72c686STodd Poynor 
5917130856fSLadislav Michl 	memset(&nvmem_cfg, 0, sizeof(nvmem_cfg));
5927130856fSLadislav Michl 	nvmem_cfg.name = "twl-secured-";
5937130856fSLadislav Michl 	nvmem_cfg.type = NVMEM_TYPE_BATTERY_BACKED;
5947130856fSLadislav Michl 	nvmem_cfg.reg_read = twl_nvram_read,
5957130856fSLadislav Michl 	nvmem_cfg.reg_write = twl_nvram_write,
5967130856fSLadislav Michl 	nvmem_cfg.word_size = 1;
5977130856fSLadislav Michl 	nvmem_cfg.stride = 1;
5987130856fSLadislav Michl 	if (twl_class_is_4030()) {
5997130856fSLadislav Michl 		/* 20 bytes SECURED_REG area */
6007130856fSLadislav Michl 		nvmem_cfg.size = 20;
6017130856fSLadislav Michl 		nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG;
6027130856fSLadislav Michl 		devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg);
6037130856fSLadislav Michl 		/* 8 bytes BACKUP area */
6047130856fSLadislav Michl 		nvmem_cfg.name = "twl-backup-";
6057130856fSLadislav Michl 		nvmem_cfg.size = 8;
6067130856fSLadislav Michl 		nvmem_cfg.priv = (void *)TWL4030_MODULE_BACKUP;
6077130856fSLadislav Michl 		devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg);
6087130856fSLadislav Michl 	} else {
6097130856fSLadislav Michl 		/* 8 bytes SECURED_REG area */
6107130856fSLadislav Michl 		nvmem_cfg.size = 8;
6117130856fSLadislav Michl 		nvmem_cfg.priv = (void *)TWL_MODULE_SECURED_REG;
6127130856fSLadislav Michl 		devm_rtc_nvmem_register(twl_rtc->rtc, &nvmem_cfg);
6137130856fSLadislav Michl 	}
6147130856fSLadislav Michl 
6157e72c686STodd Poynor 	return 0;
616b07682b6SSantosh Shilimkar }
617b07682b6SSantosh Shilimkar 
618b07682b6SSantosh Shilimkar /*
619ef3b7d0dSBalaji T K  * Disable all TWL RTC module interrupts.
620b07682b6SSantosh Shilimkar  * Sets status flag to free.
621b07682b6SSantosh Shilimkar  */
twl_rtc_remove(struct platform_device * pdev)622fff118c9SUwe Kleine-König static void twl_rtc_remove(struct platform_device *pdev)
623b07682b6SSantosh Shilimkar {
624e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
625e3e7f95bSNicolae Rosia 
626b07682b6SSantosh Shilimkar 	/* leave rtc running, but disable irqs */
627e3e7f95bSNicolae Rosia 	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
628e3e7f95bSNicolae Rosia 	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
629e3e7f95bSNicolae Rosia 	if (twl_rtc->class == TWL_6030) {
630a6b49ffdSBalaji T K 		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
631a6b49ffdSBalaji T K 			REG_INT_MSK_LINE_A);
632a6b49ffdSBalaji T K 		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
633a6b49ffdSBalaji T K 			REG_INT_MSK_STS_A);
634a6b49ffdSBalaji T K 	}
635b07682b6SSantosh Shilimkar }
636b07682b6SSantosh Shilimkar 
twl_rtc_shutdown(struct platform_device * pdev)637ef3b7d0dSBalaji T K static void twl_rtc_shutdown(struct platform_device *pdev)
638b07682b6SSantosh Shilimkar {
639e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
640e3e7f95bSNicolae Rosia 
641b07682b6SSantosh Shilimkar 	/* mask timer interrupts, but leave alarm interrupts on to enable
642b07682b6SSantosh Shilimkar 	   power-on when alarm is triggered */
643e3e7f95bSNicolae Rosia 	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
644b07682b6SSantosh Shilimkar }
645b07682b6SSantosh Shilimkar 
646b9d8c460SJingoo Han #ifdef CONFIG_PM_SLEEP
twl_rtc_suspend(struct device * dev)647b9d8c460SJingoo Han static int twl_rtc_suspend(struct device *dev)
648b07682b6SSantosh Shilimkar {
649e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
650b07682b6SSantosh Shilimkar 
651e3e7f95bSNicolae Rosia 	twl_rtc->irqstat = twl_rtc->rtc_irq_bits;
652e3e7f95bSNicolae Rosia 
653e3e7f95bSNicolae Rosia 	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
654b07682b6SSantosh Shilimkar 	return 0;
655b07682b6SSantosh Shilimkar }
656b07682b6SSantosh Shilimkar 
twl_rtc_resume(struct device * dev)657b9d8c460SJingoo Han static int twl_rtc_resume(struct device *dev)
658b07682b6SSantosh Shilimkar {
659e3e7f95bSNicolae Rosia 	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
660e3e7f95bSNicolae Rosia 
661e3e7f95bSNicolae Rosia 	set_rtc_irq_bit(twl_rtc, twl_rtc->irqstat);
662b07682b6SSantosh Shilimkar 	return 0;
663b07682b6SSantosh Shilimkar }
664b07682b6SSantosh Shilimkar #endif
665b07682b6SSantosh Shilimkar 
666b9d8c460SJingoo Han static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume);
667b9d8c460SJingoo Han 
668948170f8SBenoit Cousson static const struct of_device_id twl_rtc_of_match[] = {
669948170f8SBenoit Cousson 	{.compatible = "ti,twl4030-rtc", },
670948170f8SBenoit Cousson 	{ },
671948170f8SBenoit Cousson };
672948170f8SBenoit Cousson MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
673b07682b6SSantosh Shilimkar 
674b07682b6SSantosh Shilimkar static struct platform_driver twl4030rtc_driver = {
675ef3b7d0dSBalaji T K 	.probe		= twl_rtc_probe,
676fff118c9SUwe Kleine-König 	.remove_new	= twl_rtc_remove,
677ef3b7d0dSBalaji T K 	.shutdown	= twl_rtc_shutdown,
678b07682b6SSantosh Shilimkar 	.driver		= {
679ef3b7d0dSBalaji T K 		.name		= "twl_rtc",
680b9d8c460SJingoo Han 		.pm		= &twl_rtc_pm_ops,
6811c02cbfeSNicolae Rosia 		.of_match_table = twl_rtc_of_match,
682b07682b6SSantosh Shilimkar 	},
683b07682b6SSantosh Shilimkar };
684b07682b6SSantosh Shilimkar 
6855ee67484SPeter Ujfalusi module_platform_driver(twl4030rtc_driver);
686b07682b6SSantosh Shilimkar 
687b07682b6SSantosh Shilimkar MODULE_AUTHOR("Texas Instruments, MontaVista Software");
688b07682b6SSantosh Shilimkar MODULE_LICENSE("GPL");
689