xref: /linux/drivers/rtc/rtc-twl.c (revision 948170f8944dfd29d13612fff48110a9814daeb1)
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 
179b07682b6SSantosh Shilimkar 	val = rtc_irq_bits | bit;
180b07682b6SSantosh Shilimkar 	val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
181ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
182b07682b6SSantosh Shilimkar 	if (ret == 0)
183b07682b6SSantosh Shilimkar 		rtc_irq_bits = val;
184b07682b6SSantosh Shilimkar 
185b07682b6SSantosh Shilimkar 	return ret;
186b07682b6SSantosh Shilimkar }
187b07682b6SSantosh Shilimkar 
188b07682b6SSantosh Shilimkar /*
189b07682b6SSantosh Shilimkar  * Disable update and/or alarm interrupts.
190b07682b6SSantosh Shilimkar  */
191b07682b6SSantosh Shilimkar static int mask_rtc_irq_bit(unsigned char bit)
192b07682b6SSantosh Shilimkar {
193b07682b6SSantosh Shilimkar 	unsigned char val;
194b07682b6SSantosh Shilimkar 	int ret;
195b07682b6SSantosh Shilimkar 
196b07682b6SSantosh Shilimkar 	val = rtc_irq_bits & ~bit;
197ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);
198b07682b6SSantosh Shilimkar 	if (ret == 0)
199b07682b6SSantosh Shilimkar 		rtc_irq_bits = val;
200b07682b6SSantosh Shilimkar 
201b07682b6SSantosh Shilimkar 	return ret;
202b07682b6SSantosh Shilimkar }
203b07682b6SSantosh Shilimkar 
204ef3b7d0dSBalaji T K static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
205b07682b6SSantosh Shilimkar {
206b07682b6SSantosh Shilimkar 	int ret;
207b07682b6SSantosh Shilimkar 
208b07682b6SSantosh Shilimkar 	if (enabled)
209b07682b6SSantosh Shilimkar 		ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
210b07682b6SSantosh Shilimkar 	else
211b07682b6SSantosh Shilimkar 		ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
212b07682b6SSantosh Shilimkar 
213b07682b6SSantosh Shilimkar 	return ret;
214b07682b6SSantosh Shilimkar }
215b07682b6SSantosh Shilimkar 
216b07682b6SSantosh Shilimkar /*
217ef3b7d0dSBalaji T K  * Gets current TWL RTC time and date parameters.
218b07682b6SSantosh Shilimkar  *
219b07682b6SSantosh Shilimkar  * The RTC's time/alarm representation is not what gmtime(3) requires
220b07682b6SSantosh Shilimkar  * Linux to use:
221b07682b6SSantosh Shilimkar  *
222b07682b6SSantosh Shilimkar  *  - Months are 1..12 vs Linux 0-11
223b07682b6SSantosh Shilimkar  *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
224b07682b6SSantosh Shilimkar  */
225ef3b7d0dSBalaji T K static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
226b07682b6SSantosh Shilimkar {
227b07682b6SSantosh Shilimkar 	unsigned char rtc_data[ALL_TIME_REGS + 1];
228b07682b6SSantosh Shilimkar 	int ret;
229b07682b6SSantosh Shilimkar 	u8 save_control;
230b07682b6SSantosh Shilimkar 
231ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
232b07682b6SSantosh Shilimkar 	if (ret < 0)
233b07682b6SSantosh Shilimkar 		return ret;
234b07682b6SSantosh Shilimkar 
235b07682b6SSantosh Shilimkar 	save_control |= BIT_RTC_CTRL_REG_GET_TIME_M;
236b07682b6SSantosh Shilimkar 
237ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
238b07682b6SSantosh Shilimkar 	if (ret < 0)
239b07682b6SSantosh Shilimkar 		return ret;
240b07682b6SSantosh Shilimkar 
241ef3b7d0dSBalaji T K 	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
242a6b49ffdSBalaji T K 			(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
243b07682b6SSantosh Shilimkar 
244b07682b6SSantosh Shilimkar 	if (ret < 0) {
245b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_read_time error %d\n", ret);
246b07682b6SSantosh Shilimkar 		return ret;
247b07682b6SSantosh Shilimkar 	}
248b07682b6SSantosh Shilimkar 
249b07682b6SSantosh Shilimkar 	tm->tm_sec = bcd2bin(rtc_data[0]);
250b07682b6SSantosh Shilimkar 	tm->tm_min = bcd2bin(rtc_data[1]);
251b07682b6SSantosh Shilimkar 	tm->tm_hour = bcd2bin(rtc_data[2]);
252b07682b6SSantosh Shilimkar 	tm->tm_mday = bcd2bin(rtc_data[3]);
253b07682b6SSantosh Shilimkar 	tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
254b07682b6SSantosh Shilimkar 	tm->tm_year = bcd2bin(rtc_data[5]) + 100;
255b07682b6SSantosh Shilimkar 
256b07682b6SSantosh Shilimkar 	return ret;
257b07682b6SSantosh Shilimkar }
258b07682b6SSantosh Shilimkar 
259ef3b7d0dSBalaji T K static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
260b07682b6SSantosh Shilimkar {
261b07682b6SSantosh Shilimkar 	unsigned char save_control;
262b07682b6SSantosh Shilimkar 	unsigned char rtc_data[ALL_TIME_REGS + 1];
263b07682b6SSantosh Shilimkar 	int ret;
264b07682b6SSantosh Shilimkar 
265b07682b6SSantosh Shilimkar 	rtc_data[1] = bin2bcd(tm->tm_sec);
266b07682b6SSantosh Shilimkar 	rtc_data[2] = bin2bcd(tm->tm_min);
267b07682b6SSantosh Shilimkar 	rtc_data[3] = bin2bcd(tm->tm_hour);
268b07682b6SSantosh Shilimkar 	rtc_data[4] = bin2bcd(tm->tm_mday);
269b07682b6SSantosh Shilimkar 	rtc_data[5] = bin2bcd(tm->tm_mon + 1);
270b07682b6SSantosh Shilimkar 	rtc_data[6] = bin2bcd(tm->tm_year - 100);
271b07682b6SSantosh Shilimkar 
272b07682b6SSantosh Shilimkar 	/* Stop RTC while updating the TC registers */
273ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
274b07682b6SSantosh Shilimkar 	if (ret < 0)
275b07682b6SSantosh Shilimkar 		goto out;
276b07682b6SSantosh Shilimkar 
277b07682b6SSantosh Shilimkar 	save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
2788f6b0dd3SJesper Juhl 	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
279b07682b6SSantosh Shilimkar 	if (ret < 0)
280b07682b6SSantosh Shilimkar 		goto out;
281b07682b6SSantosh Shilimkar 
282b07682b6SSantosh Shilimkar 	/* update all the time registers in one shot */
283ef3b7d0dSBalaji T K 	ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
284a6b49ffdSBalaji T K 		(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
285b07682b6SSantosh Shilimkar 	if (ret < 0) {
286b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_set_time error %d\n", ret);
287b07682b6SSantosh Shilimkar 		goto out;
288b07682b6SSantosh Shilimkar 	}
289b07682b6SSantosh Shilimkar 
290b07682b6SSantosh Shilimkar 	/* Start back RTC */
291b07682b6SSantosh Shilimkar 	save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
292ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);
293b07682b6SSantosh Shilimkar 
294b07682b6SSantosh Shilimkar out:
295b07682b6SSantosh Shilimkar 	return ret;
296b07682b6SSantosh Shilimkar }
297b07682b6SSantosh Shilimkar 
298b07682b6SSantosh Shilimkar /*
299ef3b7d0dSBalaji T K  * Gets current TWL RTC alarm time.
300b07682b6SSantosh Shilimkar  */
301ef3b7d0dSBalaji T K static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
302b07682b6SSantosh Shilimkar {
303b07682b6SSantosh Shilimkar 	unsigned char rtc_data[ALL_TIME_REGS + 1];
304b07682b6SSantosh Shilimkar 	int ret;
305b07682b6SSantosh Shilimkar 
306ef3b7d0dSBalaji T K 	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
307a6b49ffdSBalaji T K 			(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
308b07682b6SSantosh Shilimkar 	if (ret < 0) {
309b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_read_alarm error %d\n", ret);
310b07682b6SSantosh Shilimkar 		return ret;
311b07682b6SSantosh Shilimkar 	}
312b07682b6SSantosh Shilimkar 
313b07682b6SSantosh Shilimkar 	/* some of these fields may be wildcard/"match all" */
314b07682b6SSantosh Shilimkar 	alm->time.tm_sec = bcd2bin(rtc_data[0]);
315b07682b6SSantosh Shilimkar 	alm->time.tm_min = bcd2bin(rtc_data[1]);
316b07682b6SSantosh Shilimkar 	alm->time.tm_hour = bcd2bin(rtc_data[2]);
317b07682b6SSantosh Shilimkar 	alm->time.tm_mday = bcd2bin(rtc_data[3]);
318b07682b6SSantosh Shilimkar 	alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
319b07682b6SSantosh Shilimkar 	alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
320b07682b6SSantosh Shilimkar 
321b07682b6SSantosh Shilimkar 	/* report cached alarm enable state */
322b07682b6SSantosh Shilimkar 	if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
323b07682b6SSantosh Shilimkar 		alm->enabled = 1;
324b07682b6SSantosh Shilimkar 
325b07682b6SSantosh Shilimkar 	return ret;
326b07682b6SSantosh Shilimkar }
327b07682b6SSantosh Shilimkar 
328ef3b7d0dSBalaji T K static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
329b07682b6SSantosh Shilimkar {
330b07682b6SSantosh Shilimkar 	unsigned char alarm_data[ALL_TIME_REGS + 1];
331b07682b6SSantosh Shilimkar 	int ret;
332b07682b6SSantosh Shilimkar 
333ef3b7d0dSBalaji T K 	ret = twl_rtc_alarm_irq_enable(dev, 0);
334b07682b6SSantosh Shilimkar 	if (ret)
335b07682b6SSantosh Shilimkar 		goto out;
336b07682b6SSantosh Shilimkar 
337b07682b6SSantosh Shilimkar 	alarm_data[1] = bin2bcd(alm->time.tm_sec);
338b07682b6SSantosh Shilimkar 	alarm_data[2] = bin2bcd(alm->time.tm_min);
339b07682b6SSantosh Shilimkar 	alarm_data[3] = bin2bcd(alm->time.tm_hour);
340b07682b6SSantosh Shilimkar 	alarm_data[4] = bin2bcd(alm->time.tm_mday);
341b07682b6SSantosh Shilimkar 	alarm_data[5] = bin2bcd(alm->time.tm_mon + 1);
342b07682b6SSantosh Shilimkar 	alarm_data[6] = bin2bcd(alm->time.tm_year - 100);
343b07682b6SSantosh Shilimkar 
344b07682b6SSantosh Shilimkar 	/* update all the alarm registers in one shot */
345ef3b7d0dSBalaji T K 	ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
346a6b49ffdSBalaji T K 		(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);
347b07682b6SSantosh Shilimkar 	if (ret) {
348b07682b6SSantosh Shilimkar 		dev_err(dev, "rtc_set_alarm error %d\n", ret);
349b07682b6SSantosh Shilimkar 		goto out;
350b07682b6SSantosh Shilimkar 	}
351b07682b6SSantosh Shilimkar 
352b07682b6SSantosh Shilimkar 	if (alm->enabled)
353ef3b7d0dSBalaji T K 		ret = twl_rtc_alarm_irq_enable(dev, 1);
354b07682b6SSantosh Shilimkar out:
355b07682b6SSantosh Shilimkar 	return ret;
356b07682b6SSantosh Shilimkar }
357b07682b6SSantosh Shilimkar 
358ef3b7d0dSBalaji T K static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)
359b07682b6SSantosh Shilimkar {
360b07682b6SSantosh Shilimkar 	unsigned long events = 0;
361b07682b6SSantosh Shilimkar 	int ret = IRQ_NONE;
362b07682b6SSantosh Shilimkar 	int res;
363b07682b6SSantosh Shilimkar 	u8 rd_reg;
364b07682b6SSantosh Shilimkar 
365ef3b7d0dSBalaji T K 	res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
366b07682b6SSantosh Shilimkar 	if (res)
367b07682b6SSantosh Shilimkar 		goto out;
368b07682b6SSantosh Shilimkar 	/*
369b07682b6SSantosh Shilimkar 	 * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
370b07682b6SSantosh Shilimkar 	 * only one (ALARM or RTC) interrupt source may be enabled
371b07682b6SSantosh Shilimkar 	 * at time, we also could check our results
372b07682b6SSantosh Shilimkar 	 * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
373b07682b6SSantosh Shilimkar 	 */
374b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
375b07682b6SSantosh Shilimkar 		events |= RTC_IRQF | RTC_AF;
376b07682b6SSantosh Shilimkar 	else
377b07682b6SSantosh Shilimkar 		events |= RTC_IRQF | RTC_UF;
378b07682b6SSantosh Shilimkar 
379ef3b7d0dSBalaji T K 	res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,
380b07682b6SSantosh Shilimkar 				   REG_RTC_STATUS_REG);
381b07682b6SSantosh Shilimkar 	if (res)
382b07682b6SSantosh Shilimkar 		goto out;
383b07682b6SSantosh Shilimkar 
384a6b49ffdSBalaji T K 	if (twl_class_is_4030()) {
385b07682b6SSantosh Shilimkar 		/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
386b07682b6SSantosh Shilimkar 		 * needs 2 reads to clear the interrupt. One read is done in
387ef3b7d0dSBalaji T K 		 * do_twl_pwrirq(). Doing the second read, to clear
388b07682b6SSantosh Shilimkar 		 * the bit.
389b07682b6SSantosh Shilimkar 		 *
390b07682b6SSantosh Shilimkar 		 * FIXME the reason PWR_ISR1 needs an extra read is that
391b07682b6SSantosh Shilimkar 		 * RTC_IF retriggered until we cleared REG_ALARM_M above.
392b07682b6SSantosh Shilimkar 		 * But re-reading like this is a bad hack; by doing so we
393b07682b6SSantosh Shilimkar 		 * risk wrongly clearing status for some other IRQ (losing
394b07682b6SSantosh Shilimkar 		 * the interrupt).  Be smarter about handling RTC_UF ...
395b07682b6SSantosh Shilimkar 		 */
396fc7b92fcSBalaji T K 		res = twl_i2c_read_u8(TWL4030_MODULE_INT,
397b07682b6SSantosh Shilimkar 			&rd_reg, TWL4030_INT_PWR_ISR1);
398b07682b6SSantosh Shilimkar 		if (res)
399b07682b6SSantosh Shilimkar 			goto out;
400a6b49ffdSBalaji T K 	}
401b07682b6SSantosh Shilimkar 
402b07682b6SSantosh Shilimkar 	/* Notify RTC core on event */
403b07682b6SSantosh Shilimkar 	rtc_update_irq(rtc, 1, events);
404b07682b6SSantosh Shilimkar 
405b07682b6SSantosh Shilimkar 	ret = IRQ_HANDLED;
406b07682b6SSantosh Shilimkar out:
407b07682b6SSantosh Shilimkar 	return ret;
408b07682b6SSantosh Shilimkar }
409b07682b6SSantosh Shilimkar 
410ef3b7d0dSBalaji T K static struct rtc_class_ops twl_rtc_ops = {
411ef3b7d0dSBalaji T K 	.read_time	= twl_rtc_read_time,
412ef3b7d0dSBalaji T K 	.set_time	= twl_rtc_set_time,
413ef3b7d0dSBalaji T K 	.read_alarm	= twl_rtc_read_alarm,
414ef3b7d0dSBalaji T K 	.set_alarm	= twl_rtc_set_alarm,
415ef3b7d0dSBalaji T K 	.alarm_irq_enable = twl_rtc_alarm_irq_enable,
416b07682b6SSantosh Shilimkar };
417b07682b6SSantosh Shilimkar 
418b07682b6SSantosh Shilimkar /*----------------------------------------------------------------------*/
419b07682b6SSantosh Shilimkar 
420ef3b7d0dSBalaji T K static int __devinit twl_rtc_probe(struct platform_device *pdev)
421b07682b6SSantosh Shilimkar {
422b07682b6SSantosh Shilimkar 	struct rtc_device *rtc;
4237e72c686STodd Poynor 	int ret = -EINVAL;
424b07682b6SSantosh Shilimkar 	int irq = platform_get_irq(pdev, 0);
425b07682b6SSantosh Shilimkar 	u8 rd_reg;
426b07682b6SSantosh Shilimkar 
427b07682b6SSantosh Shilimkar 	if (irq <= 0)
4287e72c686STodd Poynor 		goto out1;
429b07682b6SSantosh Shilimkar 
430ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);
431b07682b6SSantosh Shilimkar 	if (ret < 0)
432b07682b6SSantosh Shilimkar 		goto out1;
433b07682b6SSantosh Shilimkar 
434b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
435b07682b6SSantosh Shilimkar 		dev_warn(&pdev->dev, "Power up reset detected.\n");
436b07682b6SSantosh Shilimkar 
437b07682b6SSantosh Shilimkar 	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
438b07682b6SSantosh Shilimkar 		dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");
439b07682b6SSantosh Shilimkar 
440b07682b6SSantosh Shilimkar 	/* Clear RTC Power up reset and pending alarm interrupts */
441ef3b7d0dSBalaji T K 	ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);
442b07682b6SSantosh Shilimkar 	if (ret < 0)
443b07682b6SSantosh Shilimkar 		goto out1;
444b07682b6SSantosh Shilimkar 
445a6b49ffdSBalaji T K 	if (twl_class_is_6030()) {
446a6b49ffdSBalaji T K 		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
447a6b49ffdSBalaji T K 			REG_INT_MSK_LINE_A);
448a6b49ffdSBalaji T K 		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
449a6b49ffdSBalaji T K 			REG_INT_MSK_STS_A);
450a6b49ffdSBalaji T K 	}
451a6b49ffdSBalaji T K 
452b07682b6SSantosh Shilimkar 	/* Check RTC module status, Enable if it is off */
453ef3b7d0dSBalaji T K 	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);
454b07682b6SSantosh Shilimkar 	if (ret < 0)
4557e72c686STodd Poynor 		goto out1;
456b07682b6SSantosh Shilimkar 
457b07682b6SSantosh Shilimkar 	if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) {
458ef3b7d0dSBalaji T K 		dev_info(&pdev->dev, "Enabling TWL-RTC.\n");
459b07682b6SSantosh Shilimkar 		rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M;
460ef3b7d0dSBalaji T K 		ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);
461b07682b6SSantosh Shilimkar 		if (ret < 0)
4627e72c686STodd Poynor 			goto out1;
463b07682b6SSantosh Shilimkar 	}
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 
553*948170f8SBenoit Cousson static const struct of_device_id twl_rtc_of_match[] = {
554*948170f8SBenoit Cousson 	{.compatible = "ti,twl4030-rtc", },
555*948170f8SBenoit Cousson 	{ },
556*948170f8SBenoit Cousson };
557*948170f8SBenoit 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",
569*948170f8SBenoit 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