aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorOpensource [Steve Twiss] <stwiss.opensource@diasemi.com>2014-06-06 17:36:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2014-06-06 19:08:08 -0400
commitc2a57550fec132c1e184c42ea13a619f9a9980e5 (patch)
tree5bd876d811a1f8b13dc231b423aaca427fd779af /drivers/rtc
parent1fcbe42c1b763456b56d492c31e06e27547b0481 (diff)
rtc: da9063: RTC driver
Add the RTC driver for DA9063. [akpm@linux-foundation.org: coding-style tweaks] Signed-off-by: Opensource [Steve Twiss] <stwiss.opensource@diasemi.com> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Lee Jones <lee.jones@linaro.org> Cc: Mark Brown <broonie@linaro.org> Cc: Philipp Zabel <p.zabel@pengutronix.de> Cc: Samuel Ortiz <sameo@linux.intel.com> Cc: David Dajun Chen <david.chen@diasemi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-da9063.c333
3 files changed, 344 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 486d34b225d5..71988b69eca6 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -777,6 +777,16 @@ config RTC_DRV_DA9055
777 This driver can also be built as a module. If so, the module 777 This driver can also be built as a module. If so, the module
778 will be called rtc-da9055 778 will be called rtc-da9055
779 779
780config RTC_DRV_DA9063
781 tristate "Dialog Semiconductor DA9063 RTC"
782 depends on MFD_DA9063
783 help
784 If you say yes here you will get support for the RTC subsystem
785 of the Dialog Semiconductor DA9063.
786
787 This driver can also be built as a module. If so, the module
788 will be called "rtc-da9063".
789
780config RTC_DRV_EFI 790config RTC_DRV_EFI
781 tristate "EFI RTC" 791 tristate "EFI RTC"
782 depends on IA64 792 depends on IA64
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 9d7775534a3d..70347d041d10 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
32obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o 32obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
33obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o 33obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
34obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o 34obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
35obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
35obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o 36obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
36obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o 37obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
37obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o 38obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
new file mode 100644
index 000000000000..595393098b09
--- /dev/null
+++ b/drivers/rtc/rtc-da9063.c
@@ -0,0 +1,333 @@
1/* rtc-da9063.c - Real time clock device driver for DA9063
2 * Copyright (C) 2013-14 Dialog Semiconductor Ltd.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 */
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/platform_device.h>
19#include <linux/interrupt.h>
20#include <linux/rtc.h>
21#include <linux/slab.h>
22#include <linux/delay.h>
23#include <linux/regmap.h>
24#include <linux/mfd/da9063/registers.h>
25#include <linux/mfd/da9063/core.h>
26
27#define YEARS_TO_DA9063(year) ((year) - 100)
28#define MONTHS_TO_DA9063(month) ((month) + 1)
29#define YEARS_FROM_DA9063(year) ((year) + 100)
30#define MONTHS_FROM_DA9063(month) ((month) - 1)
31
32#define RTC_DATA_LEN (DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1)
33#define RTC_SEC 0
34#define RTC_MIN 1
35#define RTC_HOUR 2
36#define RTC_DAY 3
37#define RTC_MONTH 4
38#define RTC_YEAR 5
39
40struct da9063_rtc {
41 struct rtc_device *rtc_dev;
42 struct da9063 *hw;
43 struct rtc_time alarm_time;
44 bool rtc_sync;
45};
46
47static void da9063_data_to_tm(u8 *data, struct rtc_time *tm)
48{
49 tm->tm_sec = data[RTC_SEC] & DA9063_COUNT_SEC_MASK;
50 tm->tm_min = data[RTC_MIN] & DA9063_COUNT_MIN_MASK;
51 tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK;
52 tm->tm_mday = data[RTC_DAY] & DA9063_COUNT_DAY_MASK;
53 tm->tm_mon = MONTHS_FROM_DA9063(data[RTC_MONTH] &
54 DA9063_COUNT_MONTH_MASK);
55 tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] &
56 DA9063_COUNT_YEAR_MASK);
57}
58
59static void da9063_tm_to_data(struct rtc_time *tm, u8 *data)
60{
61 data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK;
62 data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK;
63
64 data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK;
65 data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK;
66
67 data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK;
68 data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK;
69
70 data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK;
71 data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK;
72
73 data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK;
74 data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) &
75 DA9063_COUNT_MONTH_MASK;
76
77 data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK;
78 data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) &
79 DA9063_COUNT_YEAR_MASK;
80}
81
82static int da9063_rtc_stop_alarm(struct device *dev)
83{
84 struct da9063_rtc *rtc = dev_get_drvdata(dev);
85
86 return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
87 DA9063_ALARM_ON, 0);
88}
89
90static int da9063_rtc_start_alarm(struct device *dev)
91{
92 struct da9063_rtc *rtc = dev_get_drvdata(dev);
93
94 return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
95 DA9063_ALARM_ON, DA9063_ALARM_ON);
96}
97
98static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm)
99{
100 struct da9063_rtc *rtc = dev_get_drvdata(dev);
101 unsigned long tm_secs;
102 unsigned long al_secs;
103 u8 data[RTC_DATA_LEN];
104 int ret;
105
106 ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S,
107 data, RTC_DATA_LEN);
108 if (ret < 0) {
109 dev_err(dev, "Failed to read RTC time data: %d\n", ret);
110 return ret;
111 }
112
113 if (!(data[RTC_SEC] & DA9063_RTC_READ)) {
114 dev_dbg(dev, "RTC not yet ready to be read by the host\n");
115 return -EINVAL;
116 }
117
118 da9063_data_to_tm(data, tm);
119
120 rtc_tm_to_time(tm, &tm_secs);
121 rtc_tm_to_time(&rtc->alarm_time, &al_secs);
122
123 /* handle the rtc synchronisation delay */
124 if (rtc->rtc_sync == true && al_secs - tm_secs == 1)
125 memcpy(tm, &rtc->alarm_time, sizeof(struct rtc_time));
126 else
127 rtc->rtc_sync = false;
128
129 return rtc_valid_tm(tm);
130}
131
132static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm)
133{
134 struct da9063_rtc *rtc = dev_get_drvdata(dev);
135 u8 data[RTC_DATA_LEN];
136 int ret;
137
138 da9063_tm_to_data(tm, data);
139 ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S,
140 data, RTC_DATA_LEN);
141 if (ret < 0)
142 dev_err(dev, "Failed to set RTC time data: %d\n", ret);
143
144 return ret;
145}
146
147static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
148{
149 struct da9063_rtc *rtc = dev_get_drvdata(dev);
150 u8 data[RTC_DATA_LEN];
151 int ret;
152 unsigned int val;
153
154 ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_ALARM_S,
155 &data[RTC_SEC], RTC_DATA_LEN);
156 if (ret < 0)
157 return ret;
158
159 da9063_data_to_tm(data, &alrm->time);
160
161 alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON);
162
163 ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val);
164 if (ret < 0)
165 return ret;
166
167 if (val & (DA9063_E_ALARM))
168 alrm->pending = 1;
169 else
170 alrm->pending = 0;
171
172 return 0;
173}
174
175static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
176{
177 struct da9063_rtc *rtc = dev_get_drvdata(dev);
178 u8 data[RTC_DATA_LEN];
179 int ret;
180
181 da9063_tm_to_data(&alrm->time, data);
182
183 ret = da9063_rtc_stop_alarm(dev);
184 if (ret < 0) {
185 dev_err(dev, "Failed to stop alarm: %d\n", ret);
186 return ret;
187 }
188
189 ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_ALARM_S,
190 data, RTC_DATA_LEN);
191 if (ret < 0) {
192 dev_err(dev, "Failed to write alarm: %d\n", ret);
193 return ret;
194 }
195
196 rtc->alarm_time = alrm->time;
197
198 if (alrm->enabled) {
199 ret = da9063_rtc_start_alarm(dev);
200 if (ret < 0) {
201 dev_err(dev, "Failed to start alarm: %d\n", ret);
202 return ret;
203 }
204 }
205
206 return ret;
207}
208
209static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
210{
211 if (enabled)
212 return da9063_rtc_start_alarm(dev);
213 else
214 return da9063_rtc_stop_alarm(dev);
215}
216
217static irqreturn_t da9063_alarm_event(int irq, void *data)
218{
219 struct da9063_rtc *rtc = data;
220
221 regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
222 DA9063_ALARM_ON, 0);
223
224 rtc->rtc_sync = true;
225 rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
226
227 return IRQ_HANDLED;
228}
229
230static const struct rtc_class_ops da9063_rtc_ops = {
231 .read_time = da9063_rtc_read_time,
232 .set_time = da9063_rtc_set_time,
233 .read_alarm = da9063_rtc_read_alarm,
234 .set_alarm = da9063_rtc_set_alarm,
235 .alarm_irq_enable = da9063_rtc_alarm_irq_enable,
236};
237
238static int da9063_rtc_probe(struct platform_device *pdev)
239{
240 struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
241 struct da9063_rtc *rtc;
242 int irq_alarm;
243 u8 data[RTC_DATA_LEN];
244 int ret;
245
246 ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E,
247 DA9063_RTC_EN, DA9063_RTC_EN);
248 if (ret < 0) {
249 dev_err(&pdev->dev, "Failed to enable RTC\n");
250 goto err;
251 }
252
253 ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K,
254 DA9063_CRYSTAL, DA9063_CRYSTAL);
255 if (ret < 0) {
256 dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n");
257 goto err;
258 }
259
260 ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S,
261 DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM,
262 0);
263 if (ret < 0) {
264 dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
265 goto err;
266 }
267
268 ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S,
269 DA9063_ALARM_STATUS_ALARM,
270 DA9063_ALARM_STATUS_ALARM);
271 if (ret < 0) {
272 dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
273 goto err;
274 }
275
276 ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_Y,
277 DA9063_TICK_ON, 0);
278 if (ret < 0) {
279 dev_err(&pdev->dev, "Failed to disable TICKs\n");
280 goto err;
281 }
282
283 ret = regmap_bulk_read(da9063->regmap, DA9063_REG_ALARM_S,
284 data, RTC_DATA_LEN);
285 if (ret < 0) {
286 dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n",
287 ret);
288 goto err;
289 }
290
291 rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
292 if (!rtc)
293 return -ENOMEM;
294
295 platform_set_drvdata(pdev, rtc);
296
297 irq_alarm = platform_get_irq_byname(pdev, "ALARM");
298 ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
299 da9063_alarm_event,
300 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
301 "ALARM", rtc);
302 if (ret) {
303 dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
304 irq_alarm, ret);
305 goto err;
306 }
307
308 rtc->hw = da9063;
309 rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
310 &da9063_rtc_ops, THIS_MODULE);
311 if (IS_ERR(rtc->rtc_dev))
312 return PTR_ERR(rtc->rtc_dev);
313
314 da9063_data_to_tm(data, &rtc->alarm_time);
315 rtc->rtc_sync = false;
316err:
317 return ret;
318}
319
320static struct platform_driver da9063_rtc_driver = {
321 .probe = da9063_rtc_probe,
322 .driver = {
323 .name = DA9063_DRVNAME_RTC,
324 .owner = THIS_MODULE,
325 },
326};
327
328module_platform_driver(da9063_rtc_driver);
329
330MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
331MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063");
332MODULE_LICENSE("GPL v2");
333MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC);