xref: /openbmc/linux/drivers/rtc/rtc-twl.c (revision 94a339d0)
1b07682b6SSantosh Shilimkar /*
2ef3b7d0dSBalaji T K  * rtc-twl.c -- TWL Real Time Clock interface
3b07682b6SSantosh Shilimkar  *
4b07682b6SSantosh Shilimkar  * Copyright (C) 2007 MontaVista Software, Inc
5b07682b6SSantosh Shilimkar  * Author: Alexandre Rusev <source@mvista.com>
6b07682b6SSantosh Shilimkar  *
7b07682b6SSantosh Shilimkar  * Based on original TI driver twl4030-rtc.c
8b07682b6SSantosh Shilimkar  *   Copyright (C) 2006 Texas Instruments, Inc.
9b07682b6SSantosh Shilimkar  *
10b07682b6SSantosh Shilimkar  * Based on rtc-omap.c
11b07682b6SSantosh Shilimkar  *   Copyright (C) 2003 MontaVista Software, Inc.
12b07682b6SSantosh Shilimkar  *   Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
13b07682b6SSantosh Shilimkar  *   Copyright (C) 2006 David Brownell
14b07682b6SSantosh Shilimkar  *
15b07682b6SSantosh Shilimkar  * This program is free software; you can redistribute it and/or
16b07682b6SSantosh Shilimkar  * modify it under the terms of the GNU General Public License
17b07682b6SSantosh Shilimkar  * as published by the Free Software Foundation; either version
18b07682b6SSantosh Shilimkar  * 2 of the License, or (at your option) any later version.
19b07682b6SSantosh Shilimkar  */
20b07682b6SSantosh Shilimkar 
21b07682b6SSantosh Shilimkar #include <linux/kernel.h>
22b07682b6SSantosh Shilimkar #include <linux/errno.h>
23b07682b6SSantosh Shilimkar #include <linux/init.h>
24b07682b6SSantosh Shilimkar #include <linux/module.h>
25b07682b6SSantosh Shilimkar #include <linux/types.h>
26b07682b6SSantosh Shilimkar #include <linux/rtc.h>
27b07682b6SSantosh Shilimkar #include <linux/bcd.h>
28b07682b6SSantosh Shilimkar #include <linux/platform_device.h>
29b07682b6SSantosh Shilimkar #include <linux/interrupt.h>
30b07682b6SSantosh Shilimkar 
31b07682b6SSantosh Shilimkar #include <linux/i2c/twl.h>
32b07682b6SSantosh Shilimkar 
33b07682b6SSantosh Shilimkar 
34b07682b6SSantosh Shilimkar /*
35b07682b6SSantosh Shilimkar  * RTC block register offsets (use TWL_MODULE_RTC)
36b07682b6SSantosh Shilimkar  */
37a6b49ffdSBalaji T K enum {
38a6b49ffdSBalaji T K 	REG_SECONDS_REG = 0,
39a6b49ffdSBalaji T K 	REG_MINUTES_REG,
40a6b49ffdSBalaji T K 	REG_HOURS_REG,
41a6b49ffdSBalaji T K 	REG_DAYS_REG,
42a6b49ffdSBalaji T K 	REG_MONTHS_REG,
43a6b49ffdSBalaji T K 	REG_YEARS_REG,
44a6b49ffdSBalaji T K 	REG_WEEKS_REG,
45b07682b6SSantosh Shilimkar 
46a6b49ffdSBalaji T K 	REG_ALARM_SECONDS_REG,
47a6b49ffdSBalaji T K 	REG_ALARM_MINUTES_REG,
48a6b49ffdSBalaji T K 	REG_ALARM_HOURS_REG,
49a6b49ffdSBalaji T K 	REG_ALARM_DAYS_REG,
50a6b49ffdSBalaji T K 	REG_ALARM_MONTHS_REG,
51a6b49ffdSBalaji T K 	REG_ALARM_YEARS_REG,
52b07682b6SSantosh Shilimkar 
53a6b49ffdSBalaji T K 	REG_RTC_CTRL_REG,
54a6b49ffdSBalaji T K 	REG_RTC_STATUS_REG,
55a6b49ffdSBalaji T K 	REG_RTC_INTERRUPTS_REG,
56b07682b6SSantosh Shilimkar 
57a6b49ffdSBalaji T K 	REG_RTC_COMP_LSB_REG,
58a6b49ffdSBalaji T K 	REG_RTC_COMP_MSB_REG,
59a6b49ffdSBalaji T K };
602e84067bSTobias Klauser static const u8 twl4030_rtc_reg_map[] = {
61a6b49ffdSBalaji T K 	[REG_SECONDS_REG] = 0x00,
62a6b49ffdSBalaji T K 	[REG_MINUTES_REG] = 0x01,
63a6b49ffdSBalaji T K 	[REG_HOURS_REG] = 0x02,
64a6b49ffdSBalaji T K 	[REG_DAYS_REG] = 0x03,
65a6b49ffdSBalaji T K 	[REG_MONTHS_REG] = 0x04,
66a6b49ffdSBalaji T K 	[REG_YEARS_REG] = 0x05,
67a6b49ffdSBalaji T K 	[REG_WEEKS_REG] = 0x06,
68a6b49ffdSBalaji T K 
69a6b49ffdSBalaji T K 	[REG_ALARM_SECONDS_REG] = 0x07,
70a6b49ffdSBalaji T K 	[REG_ALARM_MINUTES_REG] = 0x08,
71a6b49ffdSBalaji T K 	[REG_ALARM_HOURS_REG] = 0x09,
72a6b49ffdSBalaji T K 	[REG_ALARM_DAYS_REG] = 0x0A,
73a6b49ffdSBalaji T K 	[REG_ALARM_MONTHS_REG] = 0x0B,
74a6b49ffdSBalaji T K 	[REG_ALARM_YEARS_REG] = 0x0C,
75a6b49ffdSBalaji T K 
76a6b49ffdSBalaji T K 	[REG_RTC_CTRL_REG] = 0x0D,
77a6b49ffdSBalaji T K 	[REG_RTC_STATUS_REG] = 0x0E,
78a6b49ffdSBalaji T K 	[REG_RTC_INTERRUPTS_REG] = 0x0F,
79a6b49ffdSBalaji T K 
80a6b49ffdSBalaji T K 	[REG_RTC_COMP_LSB_REG] = 0x10,
81a6b49ffdSBalaji T K 	[REG_RTC_COMP_MSB_REG] = 0x11,
82a6b49ffdSBalaji T K };
832e84067bSTobias Klauser static const u8 twl6030_rtc_reg_map[] = {
84a6b49ffdSBalaji T K 	[REG_SECONDS_REG] = 0x00,
85a6b49ffdSBalaji T K 	[REG_MINUTES_REG] = 0x01,
86a6b49ffdSBalaji T K 	[REG_HOURS_REG] = 0x02,
87a6b49ffdSBalaji T K 	[REG_DAYS_REG] = 0x03,
88a6b49ffdSBalaji T K 	[REG_MONTHS_REG] = 0x04,
89a6b49ffdSBalaji T K 	[REG_YEARS_REG] = 0x05,
90a6b49ffdSBalaji T K 	[REG_WEEKS_REG] = 0x06,
91a6b49ffdSBalaji T K 
92a6b49ffdSBalaji T K 	[REG_ALARM_SECONDS_REG] = 0x08,
93a6b49ffdSBalaji T K 	[REG_ALARM_MINUTES_REG] = 0x09,
94a6b49ffdSBalaji T K 	[REG_ALARM_HOURS_REG] = 0x0A,
95a6b49ffdSBalaji T K 	[REG_ALARM_DAYS_REG] = 0x0B,
96a6b49ffdSBalaji T K 	[REG_ALARM_MONTHS_REG] = 0x0C,
97a6b49ffdSBalaji T K 	[REG_ALARM_YEARS_REG] = 0x0D,
98a6b49ffdSBalaji T K 
99a6b49ffdSBalaji T K 	[REG_RTC_CTRL_REG] = 0x10,
100a6b49ffdSBalaji T K 	[REG_RTC_STATUS_REG] = 0x11,
101a6b49ffdSBalaji T K 	[REG_RTC_INTERRUPTS_REG] = 0x12,
102a6b49ffdSBalaji T K 
103a6b49ffdSBalaji T K 	[REG_RTC_COMP_LSB_REG] = 0x13,
104a6b49ffdSBalaji T K 	[REG_RTC_COMP_MSB_REG] = 0x14,
105a6b49ffdSBalaji T K };
106b07682b6SSantosh Shilimkar 
107b07682b6SSantosh Shilimkar /* RTC_CTRL_REG bitfields */
108b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_STOP_RTC_M              0x01
109b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_ROUND_30S_M             0x02
110b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_AUTO_COMP_M             0x04
111b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_MODE_12_24_M            0x08
112b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_TEST_MODE_M             0x10
113b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M        0x20
114b07682b6SSantosh Shilimkar #define BIT_RTC_CTRL_REG_GET_TIME_M              0x40
115b07682b6SSantosh Shilimkar 
116b07682b6SSantosh Shilimkar /* RTC_STATUS_REG bitfields */
117b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_RUN_M                 0x02
118b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1S_EVENT_M            0x04
119b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1M_EVENT_M            0x08
120b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1H_EVENT_M            0x10
121b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_1D_EVENT_M            0x20
122b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_ALARM_M               0x40
123b07682b6SSantosh Shilimkar #define BIT_RTC_STATUS_REG_POWER_UP_M            0x80
124b07682b6SSantosh Shilimkar 
125b07682b6SSantosh Shilimkar /* RTC_INTERRUPTS_REG bitfields */
126b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_EVERY_M           0x03
127b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M        0x04
128b07682b6SSantosh Shilimkar #define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M        0x08
129b07682b6SSantosh Shilimkar 
130b07682b6SSantosh Shilimkar 
131b07682b6SSantosh Shilimkar /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
132b07682b6SSantosh Shilimkar #define ALL_TIME_REGS		6
133b07682b6SSantosh Shilimkar 
134b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/
135a6b49ffdSBalaji T K static u8  *rtc_reg_map;
136b07682b6SSantosh Shilimkar 
137b07682b6SSantosh Shilimkar /*
138ef3b7d0dSBalaji T K  * Supports 1 byte read from TWL RTC register.
139b07682b6SSantosh Shilimkar  */
140ef3b7d0dSBalaji T K static int twl_rtc_read_u8(u8 *data, u8 reg)
141b07682b6SSantosh Shilimkar {
142b07682b6SSantosh Shilimkar 	int ret;
143b07682b6SSantosh Shilimkar 
144a6b49ffdSBalaji T K 	ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
145b07682b6SSantosh Shilimkar 	if (ret < 0)
146ef3b7d0dSBalaji T K 		pr_err("twl_rtc: Could not read TWL"
147b07682b6SSantosh Shilimkar 		       "register %X - error %d\n", reg, ret);
148b07682b6SSantosh Shilimkar 	return ret;
149b07682b6SSantosh Shilimkar }
150b07682b6SSantosh Shilimkar 
151b07682b6SSantosh Shilimkar /*
152ef3b7d0dSBalaji T K  * Supports 1 byte write to TWL RTC registers.
153b07682b6SSantosh Shilimkar  */
154ef3b7d0dSBalaji T K static int twl_rtc_write_u8(u8 data, u8 reg)
155b07682b6SSantosh Shilimkar {
156b07682b6SSantosh Shilimkar 	int ret;
157b07682b6SSantosh Shilimkar 
158a6b49ffdSBalaji T K 	ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));
159b07682b6SSantosh Shilimkar 	if (ret < 0)
160ef3b7d0dSBalaji T K 		pr_err("twl_rtc: Could not write TWL"
161b07682b6SSantosh Shilimkar 		       "register %X - error %d\n", reg, ret);
162b07682b6SSantosh Shilimkar 	return ret;
163b07682b6SSantosh Shilimkar }
164b07682b6SSantosh Shilimkar 
165b07682b6SSantosh Shilimkar /*
166b07682b6SSantosh Shilimkar  * Cache the value for timer/alarm interrupts register; this is
167b07682b6SSantosh Shilimkar  * only changed by callers holding rtc ops lock (or resume).
168b07682b6SSantosh Shilimkar  */
169b07682b6SSantosh Shilimkar static unsigned char rtc_irq_bits;
170b07682b6SSantosh Shilimkar 
171b07682b6SSantosh Shilimkar /*
172b07682b6SSantosh Shilimkar  * Enable 1/second update and/or alarm interrupts.
173b07682b6SSantosh Shilimkar  */
174b07682b6SSantosh Shilimkar static int set_rtc_irq_bit(unsigned char bit)
175b07682b6SSantosh Shilimkar {
176b07682b6SSantosh Shilimkar 	unsigned char val;
177b07682b6SSantosh Shilimkar 	int ret;
178b07682b6SSantosh Shilimkar 
179ce9f6506SVenu Byravarasu 	/* if the bit is set, return from here */
180ce9f6506SVenu Byravarasu 	if (rtc_irq_bits & bit)
181ce9f6506SVenu Byravarasu 		return 0;
182ce9f6506SVenu Byravarasu 
183b07682b6SSantosh Shilimkar 	val = rtc_irq_bits | bit;
184b07682b6SSantosh Shilimkar 	val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
185ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
186b07682b6SSantosh Shilimkar 	if (ret == 0)
187b07682b6SSantosh Shilimkar 		rtc_irq_bits = val;
188b07682b6SSantosh Shilimkar 
189b07682b6SSantosh Shilimkar 	return ret;
190b07682b6SSantosh Shilimkar }
191b07682b6SSantosh Shilimkar 
192b07682b6SSantosh Shilimkar /*
193b07682b6SSantosh Shilimkar  * Disable update and/or alarm interrupts.
194b07682b6SSantosh Shilimkar  */
195b07682b6SSantosh Shilimkar static int mask_rtc_irq_bit(unsigned char bit)
196b07682b6SSantosh Shilimkar {
197b07682b6SSantosh Shilimkar 	unsigned char val;
198b07682b6SSantosh Shilimkar 	int ret;
199b07682b6SSantosh Shilimkar 
200ce9f6506SVenu Byravarasu 	/* if the bit is clear, return from here */
201ce9f6506SVenu Byravarasu 	if (!(rtc_irq_bits & bit))
202ce9f6506SVenu Byravarasu 		return 0;
203ce9f6506SVenu Byravarasu 
204b07682b6SSantosh Shilimkar 	val = rtc_irq_bits & ~bit;
205ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
206b07682b6SSantosh Shilimkar 	if (ret == 0)
207b07682b6SSantosh Shilimkar 		rtc_irq_bits = val;
208b07682b6SSantosh Shilimkar 
209b07682b6SSantosh Shilimkar 	return ret;
210b07682b6SSantosh Shilimkar }
211b07682b6SSantosh Shilimkar 
212ef3b7d0dSBalaji T K static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
213b07682b6SSantosh Shilimkar {
214b07682b6SSantosh Shilimkar 	int ret;
215b07682b6SSantosh Shilimkar 
216b07682b6SSantosh Shilimkar 	if (enabled)
217b07682b6SSantosh Shilimkar 		ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
218b07682b6SSantosh Shilimkar 	else
219b07682b6SSantosh Shilimkar 		ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
220b07682b6SSantosh Shilimkar 
221b07682b6SSantosh Shilimkar 	return ret;
222b07682b6SSantosh Shilimkar }
223b07682b6SSantosh Shilimkar 
224b07682b6SSantosh Shilimkar /*
225ef3b7d0dSBalaji T K  * Gets current TWL RTC time and date parameters.
226b07682b6SSantosh Shilimkar  *
227b07682b6SSantosh Shilimkar  * The RTC's time/alarm representation is not what gmtime(3) requires
228b07682b6SSantosh Shilimkar  * Linux to use:
229b07682b6SSantosh Shilimkar  *
230b07682b6SSantosh Shilimkar  *  - Months are 1..12 vs Linux 0-11
231b07682b6SSantosh Shilimkar  *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
232b07682b6SSantosh Shilimkar  */
233ef3b7d0dSBalaji T K static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
234b07682b6SSantosh Shilimkar {
235b07682b6SSantosh Shilimkar 	unsigned char rtc_data[ALL_TIME_REGS + 1];
236b07682b6SSantosh Shilimkar 	int ret;
237b07682b6SSantosh Shilimkar 	u8 save_control;
238b07682b6SSantosh Shilimkar 
239ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
240b07682b6SSantosh Shilimkar 	if (ret < 0)
241b07682b6SSantosh Shilimkar 		return ret;
242b07682b6SSantosh Shilimkar 
243b07682b6SSantosh Shilimkar 	save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
244b07682b6SSantosh Shilimkar 
245ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
246b07682b6SSantosh Shilimkar 	if (ret < 0)
247b07682b6SSantosh Shilimkar 		return ret;
248b07682b6SSantosh Shilimkar 
249ef3b7d0dSBalaji T K 	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
250a6b49ffdSBalaji T K 			(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
251b07682b6SSantosh Shilimkar 
252b07682b6SSantosh Shilimkar 	if (ret < 0) {
253b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_read_time error %d\n", ret);
254b07682b6SSantosh Shilimkar 		return ret;
255b07682b6SSantosh Shilimkar 	}
256b07682b6SSantosh Shilimkar 
257b07682b6SSantosh Shilimkar 	tm->tm_sec = bcd2bin(rtc_data[0]);
258b07682b6SSantosh Shilimkar 	tm->tm_min = bcd2bin(rtc_data[1]);
259b07682b6SSantosh Shilimkar 	tm->tm_hour = bcd2bin(rtc_data[2]);
260b07682b6SSantosh Shilimkar 	tm->tm_mday = bcd2bin(rtc_data[3]);
261b07682b6SSantosh Shilimkar 	tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
262b07682b6SSantosh Shilimkar 	tm->tm_year = bcd2bin(rtc_data[5]) + 100;
263b07682b6SSantosh Shilimkar 
264b07682b6SSantosh Shilimkar 	return ret;
265b07682b6SSantosh Shilimkar }
266b07682b6SSantosh Shilimkar 
267ef3b7d0dSBalaji T K static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
268b07682b6SSantosh Shilimkar {
269b07682b6SSantosh Shilimkar 	unsigned char save_control;
270b07682b6SSantosh Shilimkar 	unsigned char rtc_data[ALL_TIME_REGS + 1];
271b07682b6SSantosh Shilimkar 	int ret;
272b07682b6SSantosh Shilimkar 
273b07682b6SSantosh Shilimkar 	rtc_data[1] = bin2bcd(tm->tm_sec);
274b07682b6SSantosh Shilimkar 	rtc_data[2] = bin2bcd(tm->tm_min);
275b07682b6SSantosh Shilimkar 	rtc_data[3] = bin2bcd(tm->tm_hour);
276b07682b6SSantosh Shilimkar 	rtc_data[4] = bin2bcd(tm->tm_mday);
277b07682b6SSantosh Shilimkar 	rtc_data[5] = bin2bcd(tm->tm_mon + 1);
278b07682b6SSantosh Shilimkar 	rtc_data[6] = bin2bcd(tm->tm_year - 100);
279b07682b6SSantosh Shilimkar 
280b07682b6SSantosh Shilimkar 	/* Stop RTC while updating the TC registers */
281ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
282b07682b6SSantosh Shilimkar 	if (ret < 0)
283b07682b6SSantosh Shilimkar 		goto out;
284b07682b6SSantosh Shilimkar 
285b07682b6SSantosh Shilimkar 	save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
2868f6b0dd3SJesper Juhl 	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
287b07682b6SSantosh Shilimkar 	if (ret < 0)
288b07682b6SSantosh Shilimkar 		goto out;
289b07682b6SSantosh Shilimkar 
290b07682b6SSantosh Shilimkar 	/* update all the time registers in one shot */
291ef3b7d0dSBalaji T K 	ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
292a6b49ffdSBalaji T K 		(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
293b07682b6SSantosh Shilimkar 	if (ret < 0) {
294b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_set_time error %d\n", ret);
295b07682b6SSantosh Shilimkar 		goto out;
296b07682b6SSantosh Shilimkar 	}
297b07682b6SSantosh Shilimkar 
298b07682b6SSantosh Shilimkar 	/* Start back RTC */
299b07682b6SSantosh Shilimkar 	save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
300ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
301b07682b6SSantosh Shilimkar 
302b07682b6SSantosh Shilimkar out:
303b07682b6SSantosh Shilimkar 	return ret;
304b07682b6SSantosh Shilimkar }
305b07682b6SSantosh Shilimkar 
306b07682b6SSantosh Shilimkar /*
307ef3b7d0dSBalaji T K  * Gets current TWL RTC alarm time.
308b07682b6SSantosh Shilimkar  */
309ef3b7d0dSBalaji T K static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
310b07682b6SSantosh Shilimkar {
311b07682b6SSantosh Shilimkar 	unsigned char rtc_data[ALL_TIME_REGS + 1];
312b07682b6SSantosh Shilimkar 	int ret;
313b07682b6SSantosh Shilimkar 
314ef3b7d0dSBalaji T K 	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
315a6b49ffdSBalaji T K 			(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
316b07682b6SSantosh Shilimkar 	if (ret < 0) {
317b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_read_alarm error %d\n", ret);
318b07682b6SSantosh Shilimkar 		return ret;
319b07682b6SSantosh Shilimkar 	}
320b07682b6SSantosh Shilimkar 
321b07682b6SSantosh Shilimkar 	/* some of these fields may be wildcard/"match all" */
322b07682b6SSantosh Shilimkar 	alm->time.tm_sec = bcd2bin(rtc_data[0]);
323b07682b6SSantosh Shilimkar 	alm->time.tm_min = bcd2bin(rtc_data[1]);
324b07682b6SSantosh Shilimkar 	alm->time.tm_hour = bcd2bin(rtc_data[2]);
325b07682b6SSantosh Shilimkar 	alm->time.tm_mday = bcd2bin(rtc_data[3]);
326b07682b6SSantosh Shilimkar 	alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
327b07682b6SSantosh Shilimkar 	alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
328b07682b6SSantosh Shilimkar 
329b07682b6SSantosh Shilimkar 	/* report cached alarm enable state */
330b07682b6SSantosh Shilimkar 	if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
331b07682b6SSantosh Shilimkar 		alm->enabled = 1;
332b07682b6SSantosh Shilimkar 
333b07682b6SSantosh Shilimkar 	return ret;
334b07682b6SSantosh Shilimkar }
335b07682b6SSantosh Shilimkar 
336ef3b7d0dSBalaji T K static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
337b07682b6SSantosh Shilimkar {
338b07682b6SSantosh Shilimkar 	unsigned char alarm_data[ALL_TIME_REGS + 1];
339b07682b6SSantosh Shilimkar 	int ret;
340b07682b6SSantosh Shilimkar 
341ef3b7d0dSBalaji T K 	ret = twl_rtc_alarm_irq_enable(dev, 0);
342b07682b6SSantosh Shilimkar 	if (ret)
343b07682b6SSantosh Shilimkar 		goto out;
344b07682b6SSantosh Shilimkar 
345b07682b6SSantosh Shilimkar 	alarm_data[1] = bin2bcd(alm->time.tm_sec);
346b07682b6SSantosh Shilimkar 	alarm_data[2] = bin2bcd(alm->time.tm_min);
347b07682b6SSantosh Shilimkar 	alarm_data[3] = bin2bcd(alm->time.tm_hour);
348b07682b6SSantosh Shilimkar 	alarm_data[4] = bin2bcd(alm->time.tm_mday);
349b07682b6SSantosh Shilimkar 	alarm_data[5] = bin2bcd(alm->time.tm_mon + 1);
350b07682b6SSantosh Shilimkar 	alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
351b07682b6SSantosh Shilimkar 
352b07682b6SSantosh Shilimkar 	/* update all the alarm registers in one shot */
353ef3b7d0dSBalaji T K 	ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
354a6b49ffdSBalaji T K 		(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
355b07682b6SSantosh Shilimkar 	if (ret) {
356b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_set_alarm error %d\n", ret);
357b07682b6SSantosh Shilimkar 		goto out;
358b07682b6SSantosh Shilimkar 	}
359b07682b6SSantosh Shilimkar 
360b07682b6SSantosh Shilimkar 	if (alm->enabled)
361ef3b7d0dSBalaji T K 		ret = twl_rtc_alarm_irq_enable(dev, 1);
362b07682b6SSantosh Shilimkar out:
363b07682b6SSantosh Shilimkar 	return ret;
364b07682b6SSantosh Shilimkar }
365b07682b6SSantosh Shilimkar 
366ef3b7d0dSBalaji T K static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
367b07682b6SSantosh Shilimkar {
368b07682b6SSantosh Shilimkar 	unsigned long events = 0;
369b07682b6SSantosh Shilimkar 	int ret = IRQ_NONE;
370b07682b6SSantosh Shilimkar 	int res;
371b07682b6SSantosh Shilimkar 	u8 rd_reg;
372b07682b6SSantosh Shilimkar 
373ef3b7d0dSBalaji T K 	res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
374b07682b6SSantosh Shilimkar 	if (res)
375b07682b6SSantosh Shilimkar 		goto out;
376b07682b6SSantosh Shilimkar 	/*
377b07682b6SSantosh Shilimkar 	 * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
378b07682b6SSantosh Shilimkar 	 * only one (ALARM or RTC) interrupt source may be enabled
379b07682b6SSantosh Shilimkar 	 * at time, we also could check our results
380b07682b6SSantosh Shilimkar 	 * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
381b07682b6SSantosh Shilimkar 	 */
382b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
383b07682b6SSantosh Shilimkar 		events |= RTC_IRQF | RTC_AF;
384b07682b6SSantosh Shilimkar 	else
385b07682b6SSantosh Shilimkar 		events |= RTC_IRQF | RTC_UF;
386b07682b6SSantosh Shilimkar 
38794a339d0SVenu Byravarasu 	res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M,
388b07682b6SSantosh Shilimkar 				   REG_RTC_STATUS_REG);
389b07682b6SSantosh Shilimkar 	if (res)
390b07682b6SSantosh Shilimkar 		goto out;
391b07682b6SSantosh Shilimkar 
392a6b49ffdSBalaji T K 	if (twl_class_is_4030()) {
393b07682b6SSantosh Shilimkar 		/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
394b07682b6SSantosh Shilimkar 		 * needs 2 reads to clear the interrupt. One read is done in
395ef3b7d0dSBalaji T K 		 * do_twl_pwrirq(). Doing the second read, to clear
396b07682b6SSantosh Shilimkar 		 * the bit.
397b07682b6SSantosh Shilimkar 		 *
398b07682b6SSantosh Shilimkar 		 * FIXME the reason PWR_ISR1 needs an extra read is that
399b07682b6SSantosh Shilimkar 		 * RTC_IF retriggered until we cleared REG_ALARM_M above.
400b07682b6SSantosh Shilimkar 		 * But re-reading like this is a bad hack; by doing so we
401b07682b6SSantosh Shilimkar 		 * risk wrongly clearing status for some other IRQ (losing
402b07682b6SSantosh Shilimkar 		 * the interrupt).  Be smarter about handling RTC_UF ...
403b07682b6SSantosh Shilimkar 		 */
404fc7b92fcSBalaji T K 		res = twl_i2c_read_u8(TWL4030_MODULE_INT,
405b07682b6SSantosh Shilimkar 			&rd_reg, TWL4030_INT_PWR_ISR1);
406b07682b6SSantosh Shilimkar 		if (res)
407b07682b6SSantosh Shilimkar 			goto out;
408a6b49ffdSBalaji T K 	}
409b07682b6SSantosh Shilimkar 
410b07682b6SSantosh Shilimkar 	/* Notify RTC core on event */
411b07682b6SSantosh Shilimkar 	rtc_update_irq(rtc, 1, events);
412b07682b6SSantosh Shilimkar 
413b07682b6SSantosh Shilimkar 	ret = IRQ_HANDLED;
414b07682b6SSantosh Shilimkar out:
415b07682b6SSantosh Shilimkar 	return ret;
416b07682b6SSantosh Shilimkar }
417b07682b6SSantosh Shilimkar 
418ef3b7d0dSBalaji T K static struct rtc_class_ops twl_rtc_ops = {
419ef3b7d0dSBalaji T K 	.read_time	= twl_rtc_read_time,
420ef3b7d0dSBalaji T K 	.set_time	= twl_rtc_set_time,
421ef3b7d0dSBalaji T K 	.read_alarm	= twl_rtc_read_alarm,
422ef3b7d0dSBalaji T K 	.set_alarm	= twl_rtc_set_alarm,
423ef3b7d0dSBalaji T K 	.alarm_irq_enable = twl_rtc_alarm_irq_enable,
424b07682b6SSantosh Shilimkar };
425b07682b6SSantosh Shilimkar 
426b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/
427b07682b6SSantosh Shilimkar 
428ef3b7d0dSBalaji T K static int __devinit twl_rtc_probe(struct platform_device *pdev)
429b07682b6SSantosh Shilimkar {
430b07682b6SSantosh Shilimkar 	struct rtc_device *rtc;
4317e72c686STodd Poynor 	int ret = -EINVAL;
432b07682b6SSantosh Shilimkar 	int irq = platform_get_irq(pdev, 0);
433b07682b6SSantosh Shilimkar 	u8 rd_reg;
434b07682b6SSantosh Shilimkar 
435b07682b6SSantosh Shilimkar 	if (irq <= 0)
4367e72c686STodd Poynor 		goto out1;
437b07682b6SSantosh Shilimkar 
438ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
439b07682b6SSantosh Shilimkar 	if (ret < 0)
440b07682b6SSantosh Shilimkar 		goto out1;
441b07682b6SSantosh Shilimkar 
442b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
443b07682b6SSantosh Shilimkar 		dev_warn(&pdev->dev, "Power up reset detected.\n");
444b07682b6SSantosh Shilimkar 
445b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
446b07682b6SSantosh Shilimkar 		dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
447b07682b6SSantosh Shilimkar 
448b07682b6SSantosh Shilimkar 	/* Clear RTC Power up reset and pending alarm interrupts */
449ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
450b07682b6SSantosh Shilimkar 	if (ret < 0)
451b07682b6SSantosh Shilimkar 		goto out1;
452b07682b6SSantosh Shilimkar 
453a6b49ffdSBalaji T K 	if (twl_class_is_6030()) {
454a6b49ffdSBalaji T K 		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
455a6b49ffdSBalaji T K 			REG_INT_MSK_LINE_A);
456a6b49ffdSBalaji T K 		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
457a6b49ffdSBalaji T K 			REG_INT_MSK_STS_A);
458a6b49ffdSBalaji T K 	}
459a6b49ffdSBalaji T K 
460f7439bcbSVenu Byravarasu 	dev_info(&pdev->dev, "Enabling TWL-RTC\n");
461f7439bcbSVenu Byravarasu 	ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);
462b07682b6SSantosh Shilimkar 	if (ret < 0)
4637e72c686STodd Poynor 		goto out1;
464b07682b6SSantosh Shilimkar 
465b07682b6SSantosh Shilimkar 	/* init cached IRQ enable bits */
466ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);
467b07682b6SSantosh Shilimkar 	if (ret < 0)
4687e72c686STodd Poynor 		goto out1;
469b07682b6SSantosh Shilimkar 
4707e72c686STodd Poynor 	rtc = rtc_device_register(pdev->name,
4717e72c686STodd Poynor 				  &pdev->dev, &twl_rtc_ops, THIS_MODULE);
4727e72c686STodd Poynor 	if (IS_ERR(rtc)) {
4737e72c686STodd Poynor 		ret = PTR_ERR(rtc);
4747e72c686STodd Poynor 		dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
4757e72c686STodd Poynor 			PTR_ERR(rtc));
4767e72c686STodd Poynor 		goto out1;
4777e72c686STodd Poynor 	}
4787e72c686STodd Poynor 
4797e72c686STodd Poynor 	ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt,
4807e72c686STodd Poynor 				   IRQF_TRIGGER_RISING,
4817e72c686STodd Poynor 				   dev_name(&rtc->dev), rtc);
4827e72c686STodd Poynor 	if (ret < 0) {
4837e72c686STodd Poynor 		dev_err(&pdev->dev, "IRQ is not free.\n");
4847e72c686STodd Poynor 		goto out2;
4857e72c686STodd Poynor 	}
4867e72c686STodd Poynor 
4877e72c686STodd Poynor 	platform_set_drvdata(pdev, rtc);
4887e72c686STodd Poynor 	return 0;
489b07682b6SSantosh Shilimkar 
490b07682b6SSantosh Shilimkar out2:
491b07682b6SSantosh Shilimkar 	rtc_device_unregister(rtc);
4927e72c686STodd Poynor out1:
493b07682b6SSantosh Shilimkar 	return ret;
494b07682b6SSantosh Shilimkar }
495b07682b6SSantosh Shilimkar 
496b07682b6SSantosh Shilimkar /*
497ef3b7d0dSBalaji T K  * Disable all TWL RTC module interrupts.
498b07682b6SSantosh Shilimkar  * Sets status flag to free.
499b07682b6SSantosh Shilimkar  */
500ef3b7d0dSBalaji T K static int __devexit twl_rtc_remove(struct platform_device *pdev)
501b07682b6SSantosh Shilimkar {
502b07682b6SSantosh Shilimkar 	/* leave rtc running, but disable irqs */
503b07682b6SSantosh Shilimkar 	struct rtc_device *rtc = platform_get_drvdata(pdev);
504b07682b6SSantosh Shilimkar 	int irq = platform_get_irq(pdev, 0);
505b07682b6SSantosh Shilimkar 
506b07682b6SSantosh Shilimkar 	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
507b07682b6SSantosh Shilimkar 	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
508a6b49ffdSBalaji T K 	if (twl_class_is_6030()) {
509a6b49ffdSBalaji T K 		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
510a6b49ffdSBalaji T K 			REG_INT_MSK_LINE_A);
511a6b49ffdSBalaji T K 		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
512a6b49ffdSBalaji T K 			REG_INT_MSK_STS_A);
513a6b49ffdSBalaji T K 	}
514a6b49ffdSBalaji T K 
515b07682b6SSantosh Shilimkar 
516b07682b6SSantosh Shilimkar 	free_irq(irq, rtc);
517b07682b6SSantosh Shilimkar 
518b07682b6SSantosh Shilimkar 	rtc_device_unregister(rtc);
519b07682b6SSantosh Shilimkar 	platform_set_drvdata(pdev, NULL);
520b07682b6SSantosh Shilimkar 	return 0;
521b07682b6SSantosh Shilimkar }
522b07682b6SSantosh Shilimkar 
523ef3b7d0dSBalaji T K static void twl_rtc_shutdown(struct platform_device *pdev)
524b07682b6SSantosh Shilimkar {
525b07682b6SSantosh Shilimkar 	/* mask timer interrupts, but leave alarm interrupts on to enable
526b07682b6SSantosh Shilimkar 	   power-on when alarm is triggered */
527b07682b6SSantosh Shilimkar 	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
528b07682b6SSantosh Shilimkar }
529b07682b6SSantosh Shilimkar 
530b07682b6SSantosh Shilimkar #ifdef CONFIG_PM
531b07682b6SSantosh Shilimkar 
532b07682b6SSantosh Shilimkar static unsigned char irqstat;
533b07682b6SSantosh Shilimkar 
534ef3b7d0dSBalaji T K static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state)
535b07682b6SSantosh Shilimkar {
536b07682b6SSantosh Shilimkar 	irqstat = rtc_irq_bits;
537b07682b6SSantosh Shilimkar 
538b07682b6SSantosh Shilimkar 	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
539b07682b6SSantosh Shilimkar 	return 0;
540b07682b6SSantosh Shilimkar }
541b07682b6SSantosh Shilimkar 
542ef3b7d0dSBalaji T K static int twl_rtc_resume(struct platform_device *pdev)
543b07682b6SSantosh Shilimkar {
544b07682b6SSantosh Shilimkar 	set_rtc_irq_bit(irqstat);
545b07682b6SSantosh Shilimkar 	return 0;
546b07682b6SSantosh Shilimkar }
547b07682b6SSantosh Shilimkar 
548b07682b6SSantosh Shilimkar #else
549ef3b7d0dSBalaji T K #define twl_rtc_suspend NULL
550ef3b7d0dSBalaji T K #define twl_rtc_resume  NULL
551b07682b6SSantosh Shilimkar #endif
552b07682b6SSantosh Shilimkar 
553948170f8SBenoit Cousson static const struct of_device_id twl_rtc_of_match[] = {
554948170f8SBenoit Cousson 	{.compatible = "ti,twl4030-rtc", },
555948170f8SBenoit Cousson 	{ },
556948170f8SBenoit Cousson };
557948170f8SBenoit Cousson MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
558ef3b7d0dSBalaji T K MODULE_ALIAS("platform:twl_rtc");
559b07682b6SSantosh Shilimkar 
560b07682b6SSantosh Shilimkar static struct platform_driver twl4030rtc_driver = {
561ef3b7d0dSBalaji T K 	.probe		= twl_rtc_probe,
562ef3b7d0dSBalaji T K 	.remove		= __devexit_p(twl_rtc_remove),
563ef3b7d0dSBalaji T K 	.shutdown	= twl_rtc_shutdown,
564ef3b7d0dSBalaji T K 	.suspend	= twl_rtc_suspend,
565ef3b7d0dSBalaji T K 	.resume		= twl_rtc_resume,
566b07682b6SSantosh Shilimkar 	.driver		= {
567b07682b6SSantosh Shilimkar 		.owner		= THIS_MODULE,
568ef3b7d0dSBalaji T K 		.name		= "twl_rtc",
569948170f8SBenoit Cousson 		.of_match_table = twl_rtc_of_match,
570b07682b6SSantosh Shilimkar 	},
571b07682b6SSantosh Shilimkar };
572b07682b6SSantosh Shilimkar 
573ef3b7d0dSBalaji T K static int __init twl_rtc_init(void)
574b07682b6SSantosh Shilimkar {
575a6b49ffdSBalaji T K 	if (twl_class_is_4030())
576a6b49ffdSBalaji T K 		rtc_reg_map = (u8 *) twl4030_rtc_reg_map;
577a6b49ffdSBalaji T K 	else
578a6b49ffdSBalaji T K 		rtc_reg_map = (u8 *) twl6030_rtc_reg_map;
579a6b49ffdSBalaji T K 
580b07682b6SSantosh Shilimkar 	return platform_driver_register(&twl4030rtc_driver);
581b07682b6SSantosh Shilimkar }
582ef3b7d0dSBalaji T K module_init(twl_rtc_init);
583b07682b6SSantosh Shilimkar 
584ef3b7d0dSBalaji T K static void __exit twl_rtc_exit(void)
585b07682b6SSantosh Shilimkar {
586b07682b6SSantosh Shilimkar 	platform_driver_unregister(&twl4030rtc_driver);
587b07682b6SSantosh Shilimkar }
588ef3b7d0dSBalaji T K module_exit(twl_rtc_exit);
589b07682b6SSantosh Shilimkar 
590b07682b6SSantosh Shilimkar MODULE_AUTHOR("Texas Instruments, MontaVista Software");
591b07682b6SSantosh Shilimkar MODULE_LICENSE("GPL");
592