blob: 690bc398cd6c00aa6237fa00fb64b8dd1fef1330 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* drivers/rtc/rtc-msm7x00a.c
2 *
3 * Copyright (C) 2008 Google, Inc.
4 * Author: San Mehat <san@google.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/module.h>
18#include <linux/version.h>
19
20#include <linux/kernel.h>
21#include <linux/platform_device.h>
22#include <linux/init.h>
23#include <linux/types.h>
24#include <linux/rtc.h>
25#include <linux/msm_rpcrouter.h>
26
27#include <mach/msm_rpcrouter.h>
28
29#define RTC_DEBUG 0
30
31extern void msm_pm_set_max_sleep_time(int64_t sleep_time_ns);
32
33#if CONFIG_MSM_AMSS_VERSION >= 6350 || defined(CONFIG_ARCH_QSD8X50)
34#define APP_TIMEREMOTE_PDEV_NAME "rs30000048:00010000"
35#else
36#define APP_TIMEREMOTE_PDEV_NAME "rs30000048:0da5b528"
37#endif
38
39#define TIMEREMOTE_PROCEEDURE_SET_JULIAN 6
40#define TIMEREMOTE_PROCEEDURE_GET_JULIAN 7
41
42struct rpc_time_julian {
43 uint32_t year;
44 uint32_t month;
45 uint32_t day;
46 uint32_t hour;
47 uint32_t minute;
48 uint32_t second;
49 uint32_t day_of_week;
50};
51
52static struct msm_rpc_endpoint *ep;
53static struct rtc_device *rtc;
54static unsigned long rtcalarm_time;
55
56static int
57msmrtc_timeremote_set_time(struct device *dev, struct rtc_time *tm)
58{
59 int rc;
60
61 struct timeremote_set_julian_req {
62 struct rpc_request_hdr hdr;
63 uint32_t opt_arg;
64
65 struct rpc_time_julian time;
66 } req;
67
68 struct timeremote_set_julian_rep {
69 struct rpc_reply_hdr hdr;
70 } rep;
71
72 if (tm->tm_year < 1900)
73 tm->tm_year += 1900;
74
75 if (tm->tm_year < 1970)
76 return -EINVAL;
77
78#if RTC_DEBUG
79 printk(KERN_DEBUG "%s: %.2u/%.2u/%.4u %.2u:%.2u:%.2u (%.2u)\n",
80 __func__, tm->tm_mon, tm->tm_mday, tm->tm_year,
81 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
82#endif
83
84 req.opt_arg = cpu_to_be32(1);
85 req.time.year = cpu_to_be32(tm->tm_year);
86 req.time.month = cpu_to_be32(tm->tm_mon + 1);
87 req.time.day = cpu_to_be32(tm->tm_mday);
88 req.time.hour = cpu_to_be32(tm->tm_hour);
89 req.time.minute = cpu_to_be32(tm->tm_min);
90 req.time.second = cpu_to_be32(tm->tm_sec);
91 req.time.day_of_week = cpu_to_be32(tm->tm_wday);
92
93
94 rc = msm_rpc_call_reply(ep, TIMEREMOTE_PROCEEDURE_SET_JULIAN,
95 &req, sizeof(req),
96 &rep, sizeof(rep),
97 5 * HZ);
98 return rc;
99}
100
101static int
102msmrtc_timeremote_read_time(struct device *dev, struct rtc_time *tm)
103{
104 int rc;
105
106 struct timeremote_get_julian_req {
107 struct rpc_request_hdr hdr;
108 uint32_t julian_time_not_null;
109 } req;
110
111 struct timeremote_get_julian_rep {
112 struct rpc_reply_hdr hdr;
113 uint32_t opt_arg;
114 struct rpc_time_julian time;
115 } rep;
116
117 req.julian_time_not_null = cpu_to_be32(1);
118
119 rc = msm_rpc_call_reply(ep, TIMEREMOTE_PROCEEDURE_GET_JULIAN,
120 &req, sizeof(req),
121 &rep, sizeof(rep),
122 5 * HZ);
123 if (rc < 0)
124 return rc;
125
126 if (!be32_to_cpu(rep.opt_arg)) {
127 printk(KERN_ERR "%s: No data from RTC\n", __func__);
128 return -ENODATA;
129 }
130
131 tm->tm_year = be32_to_cpu(rep.time.year);
132 tm->tm_mon = be32_to_cpu(rep.time.month);
133 tm->tm_mday = be32_to_cpu(rep.time.day);
134 tm->tm_hour = be32_to_cpu(rep.time.hour);
135 tm->tm_min = be32_to_cpu(rep.time.minute);
136 tm->tm_sec = be32_to_cpu(rep.time.second);
137 tm->tm_wday = be32_to_cpu(rep.time.day_of_week);
138
139#if RTC_DEBUG
140 printk(KERN_DEBUG "%s: %.2u/%.2u/%.4u %.2u:%.2u:%.2u (%.2u)\n",
141 __func__, tm->tm_mon, tm->tm_mday, tm->tm_year,
142 tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
143#endif
144
145 tm->tm_year -= 1900; /* RTC layer expects years to start at 1900 */
146 tm->tm_mon--; /* RTC layer expects mons to be 0 based */
147
148 if (rtc_valid_tm(tm) < 0) {
149 dev_err(dev, "retrieved date/time is not valid.\n");
150 rtc_time_to_tm(0, tm);
151 }
152
153 return 0;
154}
155
156
157static int
158msmrtc_virtual_alarm_set(struct device *dev, struct rtc_wkalrm *a)
159{
160 unsigned long now = get_seconds();
161
162 if (!a->enabled) {
163 rtcalarm_time = 0;
164 return 0;
165 } else
166 rtc_tm_to_time(&a->time, &rtcalarm_time);
167
168 if (now > rtcalarm_time) {
169 printk(KERN_ERR "%s: Attempt to set alarm in the past\n",
170 __func__);
171 rtcalarm_time = 0;
172 return -EINVAL;
173 }
174
175 return 0;
176}
177
178static struct rtc_class_ops msm_rtc_ops = {
179 .read_time = msmrtc_timeremote_read_time,
180 .set_time = msmrtc_timeremote_set_time,
181 .set_alarm = msmrtc_virtual_alarm_set,
182};
183
184static void
185msmrtc_alarmtimer_expired(unsigned long _data)
186{
187#if RTC_DEBUG
188 printk(KERN_DEBUG "%s: Generating alarm event (src %lu)\n",
189 rtc->name, _data);
190#endif
191 rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
192 rtcalarm_time = 0;
193}
194
195static int
196msmrtc_probe(struct platform_device *pdev)
197{
198 struct rpcsvr_platform_device *rdev =
199 container_of(pdev, struct rpcsvr_platform_device, base);
200
201 ep = msm_rpc_connect(rdev->prog, rdev->vers, 0);
202 if (IS_ERR(ep)) {
203 printk(KERN_ERR "%s: init rpc failed! rc = %ld\n",
204 __func__, PTR_ERR(ep));
205 return PTR_ERR(ep);
206 }
207
208 rtc = rtc_device_register("msm_rtc",
209 &pdev->dev,
210 &msm_rtc_ops,
211 THIS_MODULE);
212 if (IS_ERR(rtc)) {
213 printk(KERN_ERR "%s: Can't register RTC device (%ld)\n",
214 pdev->name, PTR_ERR(rtc));
215 return PTR_ERR(rtc);
216 }
217 return 0;
218}
219
220
221static unsigned long msmrtc_get_seconds(void)
222{
223 struct rtc_time tm;
224 unsigned long now;
225
226 msmrtc_timeremote_read_time(NULL, &tm);
227 rtc_tm_to_time(&tm, &now);
228 return now;
229}
230
231static int
232msmrtc_suspend(struct platform_device *dev, pm_message_t state)
233{
234 if (rtcalarm_time) {
235 unsigned long now = msmrtc_get_seconds();
236 int diff = rtcalarm_time - now;
237 if (diff <= 0) {
238 msmrtc_alarmtimer_expired(1);
239 msm_pm_set_max_sleep_time(0);
240 return 0;
241 }
242 msm_pm_set_max_sleep_time((int64_t) ((int64_t) diff * NSEC_PER_SEC));
243 } else
244 msm_pm_set_max_sleep_time(0);
245 return 0;
246}
247
248static int
249msmrtc_resume(struct platform_device *dev)
250{
251 if (rtcalarm_time) {
252 unsigned long now = msmrtc_get_seconds();
253 int diff = rtcalarm_time - now;
254 if (diff <= 0)
255 msmrtc_alarmtimer_expired(2);
256 }
257 return 0;
258}
259
260static struct platform_driver msmrtc_driver = {
261 .probe = msmrtc_probe,
262 .suspend = msmrtc_suspend,
263 .resume = msmrtc_resume,
264 .driver = {
265 .name = APP_TIMEREMOTE_PDEV_NAME,
266 .owner = THIS_MODULE,
267 },
268};
269
270static int __init msmrtc_init(void)
271{
272 rtcalarm_time = 0;
273 return platform_driver_register(&msmrtc_driver);
274}
275
276module_init(msmrtc_init);
277
278MODULE_DESCRIPTION("RTC driver for Qualcomm MSM7x00a chipsets");
279MODULE_AUTHOR("San Mehat <san@android.com>");
280MODULE_LICENSE("GPL");