1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Real Time Clock driver for Marvell 88PM80x PMIC |
4 | * |
5 | * Copyright (c) 2012 Marvell International Ltd. |
6 | * Wenzeng Chen<wzch@marvell.com> |
7 | * Qiao Zhou <zhouqiao@marvell.com> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/mfd/core.h> |
15 | #include <linux/mfd/88pm80x.h> |
16 | #include <linux/rtc.h> |
17 | |
18 | #define PM800_RTC_COUNTER1 (0xD1) |
19 | #define PM800_RTC_COUNTER2 (0xD2) |
20 | #define PM800_RTC_COUNTER3 (0xD3) |
21 | #define PM800_RTC_COUNTER4 (0xD4) |
22 | #define PM800_RTC_EXPIRE1_1 (0xD5) |
23 | #define PM800_RTC_EXPIRE1_2 (0xD6) |
24 | #define PM800_RTC_EXPIRE1_3 (0xD7) |
25 | #define PM800_RTC_EXPIRE1_4 (0xD8) |
26 | #define PM800_RTC_TRIM1 (0xD9) |
27 | #define PM800_RTC_TRIM2 (0xDA) |
28 | #define PM800_RTC_TRIM3 (0xDB) |
29 | #define PM800_RTC_TRIM4 (0xDC) |
30 | #define PM800_RTC_EXPIRE2_1 (0xDD) |
31 | #define PM800_RTC_EXPIRE2_2 (0xDE) |
32 | #define PM800_RTC_EXPIRE2_3 (0xDF) |
33 | #define PM800_RTC_EXPIRE2_4 (0xE0) |
34 | |
35 | #define PM800_POWER_DOWN_LOG1 (0xE5) |
36 | #define PM800_POWER_DOWN_LOG2 (0xE6) |
37 | |
38 | struct pm80x_rtc_info { |
39 | struct pm80x_chip *chip; |
40 | struct regmap *map; |
41 | struct rtc_device *rtc_dev; |
42 | struct device *dev; |
43 | |
44 | int irq; |
45 | }; |
46 | |
47 | static irqreturn_t rtc_update_handler(int irq, void *data) |
48 | { |
49 | struct pm80x_rtc_info *info = (struct pm80x_rtc_info *)data; |
50 | int mask; |
51 | |
52 | mask = PM800_ALARM | PM800_ALARM_WAKEUP; |
53 | regmap_update_bits(map: info->map, PM800_RTC_CONTROL, mask: mask | PM800_ALARM1_EN, |
54 | val: mask); |
55 | rtc_update_irq(rtc: info->rtc_dev, num: 1, RTC_AF); |
56 | return IRQ_HANDLED; |
57 | } |
58 | |
59 | static int pm80x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) |
60 | { |
61 | struct pm80x_rtc_info *info = dev_get_drvdata(dev); |
62 | |
63 | if (enabled) |
64 | regmap_update_bits(map: info->map, PM800_RTC_CONTROL, |
65 | PM800_ALARM1_EN, PM800_ALARM1_EN); |
66 | else |
67 | regmap_update_bits(map: info->map, PM800_RTC_CONTROL, |
68 | PM800_ALARM1_EN, val: 0); |
69 | return 0; |
70 | } |
71 | |
72 | /* |
73 | * Calculate the next alarm time given the requested alarm time mask |
74 | * and the current time. |
75 | */ |
76 | static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, |
77 | struct rtc_time *alrm) |
78 | { |
79 | unsigned long next_time; |
80 | unsigned long now_time; |
81 | |
82 | next->tm_year = now->tm_year; |
83 | next->tm_mon = now->tm_mon; |
84 | next->tm_mday = now->tm_mday; |
85 | next->tm_hour = alrm->tm_hour; |
86 | next->tm_min = alrm->tm_min; |
87 | next->tm_sec = alrm->tm_sec; |
88 | |
89 | now_time = rtc_tm_to_time64(tm: now); |
90 | next_time = rtc_tm_to_time64(tm: next); |
91 | |
92 | if (next_time < now_time) { |
93 | /* Advance one day */ |
94 | next_time += 60 * 60 * 24; |
95 | rtc_time64_to_tm(time: next_time, tm: next); |
96 | } |
97 | } |
98 | |
99 | static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm) |
100 | { |
101 | struct pm80x_rtc_info *info = dev_get_drvdata(dev); |
102 | unsigned char buf[4]; |
103 | unsigned long ticks, base, data; |
104 | regmap_raw_read(map: info->map, PM800_RTC_EXPIRE2_1, val: buf, val_len: 4); |
105 | base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | |
106 | (buf[1] << 8) | buf[0]; |
107 | dev_dbg(info->dev, "%x-%x-%x-%x\n" , buf[0], buf[1], buf[2], buf[3]); |
108 | |
109 | /* load 32-bit read-only counter */ |
110 | regmap_raw_read(map: info->map, PM800_RTC_COUNTER1, val: buf, val_len: 4); |
111 | data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | |
112 | (buf[1] << 8) | buf[0]; |
113 | ticks = base + data; |
114 | dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n" , |
115 | base, data, ticks); |
116 | rtc_time64_to_tm(time: ticks, tm); |
117 | return 0; |
118 | } |
119 | |
120 | static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm) |
121 | { |
122 | struct pm80x_rtc_info *info = dev_get_drvdata(dev); |
123 | unsigned char buf[4]; |
124 | unsigned long ticks, base, data; |
125 | |
126 | ticks = rtc_tm_to_time64(tm); |
127 | |
128 | /* load 32-bit read-only counter */ |
129 | regmap_raw_read(map: info->map, PM800_RTC_COUNTER1, val: buf, val_len: 4); |
130 | data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | |
131 | (buf[1] << 8) | buf[0]; |
132 | base = ticks - data; |
133 | dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n" , |
134 | base, data, ticks); |
135 | buf[0] = base & 0xFF; |
136 | buf[1] = (base >> 8) & 0xFF; |
137 | buf[2] = (base >> 16) & 0xFF; |
138 | buf[3] = (base >> 24) & 0xFF; |
139 | regmap_raw_write(map: info->map, PM800_RTC_EXPIRE2_1, val: buf, val_len: 4); |
140 | |
141 | return 0; |
142 | } |
143 | |
144 | static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
145 | { |
146 | struct pm80x_rtc_info *info = dev_get_drvdata(dev); |
147 | unsigned char buf[4]; |
148 | unsigned long ticks, base, data; |
149 | int ret; |
150 | |
151 | regmap_raw_read(map: info->map, PM800_RTC_EXPIRE2_1, val: buf, val_len: 4); |
152 | base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | |
153 | (buf[1] << 8) | buf[0]; |
154 | dev_dbg(info->dev, "%x-%x-%x-%x\n" , buf[0], buf[1], buf[2], buf[3]); |
155 | |
156 | regmap_raw_read(map: info->map, PM800_RTC_EXPIRE1_1, val: buf, val_len: 4); |
157 | data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | |
158 | (buf[1] << 8) | buf[0]; |
159 | ticks = base + data; |
160 | dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n" , |
161 | base, data, ticks); |
162 | |
163 | rtc_time64_to_tm(time: ticks, tm: &alrm->time); |
164 | regmap_read(map: info->map, PM800_RTC_CONTROL, val: &ret); |
165 | alrm->enabled = (ret & PM800_ALARM1_EN) ? 1 : 0; |
166 | alrm->pending = (ret & (PM800_ALARM | PM800_ALARM_WAKEUP)) ? 1 : 0; |
167 | return 0; |
168 | } |
169 | |
170 | static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) |
171 | { |
172 | struct pm80x_rtc_info *info = dev_get_drvdata(dev); |
173 | struct rtc_time now_tm, alarm_tm; |
174 | unsigned long ticks, base, data; |
175 | unsigned char buf[4]; |
176 | int mask; |
177 | |
178 | regmap_update_bits(map: info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, val: 0); |
179 | |
180 | regmap_raw_read(map: info->map, PM800_RTC_EXPIRE2_1, val: buf, val_len: 4); |
181 | base = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | |
182 | (buf[1] << 8) | buf[0]; |
183 | dev_dbg(info->dev, "%x-%x-%x-%x\n" , buf[0], buf[1], buf[2], buf[3]); |
184 | |
185 | /* load 32-bit read-only counter */ |
186 | regmap_raw_read(map: info->map, PM800_RTC_COUNTER1, val: buf, val_len: 4); |
187 | data = ((unsigned long)buf[3] << 24) | (buf[2] << 16) | |
188 | (buf[1] << 8) | buf[0]; |
189 | ticks = base + data; |
190 | dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n" , |
191 | base, data, ticks); |
192 | |
193 | rtc_time64_to_tm(time: ticks, tm: &now_tm); |
194 | dev_dbg(info->dev, "%s, now time : %lu\n" , __func__, ticks); |
195 | rtc_next_alarm_time(next: &alarm_tm, now: &now_tm, alrm: &alrm->time); |
196 | /* get new ticks for alarm in 24 hours */ |
197 | ticks = rtc_tm_to_time64(tm: &alarm_tm); |
198 | dev_dbg(info->dev, "%s, alarm time: %lu\n" , __func__, ticks); |
199 | data = ticks - base; |
200 | |
201 | buf[0] = data & 0xff; |
202 | buf[1] = (data >> 8) & 0xff; |
203 | buf[2] = (data >> 16) & 0xff; |
204 | buf[3] = (data >> 24) & 0xff; |
205 | regmap_raw_write(map: info->map, PM800_RTC_EXPIRE1_1, val: buf, val_len: 4); |
206 | if (alrm->enabled) { |
207 | mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN; |
208 | regmap_update_bits(map: info->map, PM800_RTC_CONTROL, mask, val: mask); |
209 | } else { |
210 | mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN; |
211 | regmap_update_bits(map: info->map, PM800_RTC_CONTROL, mask, |
212 | PM800_ALARM | PM800_ALARM_WAKEUP); |
213 | } |
214 | return 0; |
215 | } |
216 | |
217 | static const struct rtc_class_ops pm80x_rtc_ops = { |
218 | .read_time = pm80x_rtc_read_time, |
219 | .set_time = pm80x_rtc_set_time, |
220 | .read_alarm = pm80x_rtc_read_alarm, |
221 | .set_alarm = pm80x_rtc_set_alarm, |
222 | .alarm_irq_enable = pm80x_rtc_alarm_irq_enable, |
223 | }; |
224 | |
225 | #ifdef CONFIG_PM_SLEEP |
226 | static int pm80x_rtc_suspend(struct device *dev) |
227 | { |
228 | return pm80x_dev_suspend(dev); |
229 | } |
230 | |
231 | static int pm80x_rtc_resume(struct device *dev) |
232 | { |
233 | return pm80x_dev_resume(dev); |
234 | } |
235 | #endif |
236 | |
237 | static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume); |
238 | |
239 | static int pm80x_rtc_probe(struct platform_device *pdev) |
240 | { |
241 | struct pm80x_chip *chip = dev_get_drvdata(dev: pdev->dev.parent); |
242 | struct pm80x_rtc_pdata *pdata = dev_get_platdata(dev: &pdev->dev); |
243 | struct pm80x_rtc_info *info; |
244 | struct device_node *node = pdev->dev.of_node; |
245 | int ret; |
246 | |
247 | if (!pdata && !node) { |
248 | dev_err(&pdev->dev, |
249 | "pm80x-rtc requires platform data or of_node\n" ); |
250 | return -EINVAL; |
251 | } |
252 | |
253 | if (!pdata) { |
254 | pdata = devm_kzalloc(dev: &pdev->dev, size: sizeof(*pdata), GFP_KERNEL); |
255 | if (!pdata) { |
256 | dev_err(&pdev->dev, "failed to allocate memory\n" ); |
257 | return -ENOMEM; |
258 | } |
259 | } |
260 | |
261 | info = |
262 | devm_kzalloc(dev: &pdev->dev, size: sizeof(struct pm80x_rtc_info), GFP_KERNEL); |
263 | if (!info) |
264 | return -ENOMEM; |
265 | info->irq = platform_get_irq(pdev, 0); |
266 | if (info->irq < 0) { |
267 | ret = -EINVAL; |
268 | goto out; |
269 | } |
270 | |
271 | info->chip = chip; |
272 | info->map = chip->regmap; |
273 | if (!info->map) { |
274 | dev_err(&pdev->dev, "no regmap!\n" ); |
275 | ret = -EINVAL; |
276 | goto out; |
277 | } |
278 | |
279 | info->dev = &pdev->dev; |
280 | dev_set_drvdata(dev: &pdev->dev, data: info); |
281 | |
282 | info->rtc_dev = devm_rtc_allocate_device(dev: &pdev->dev); |
283 | if (IS_ERR(ptr: info->rtc_dev)) |
284 | return PTR_ERR(ptr: info->rtc_dev); |
285 | |
286 | ret = pm80x_request_irq(pm80x: chip, irq: info->irq, handler: rtc_update_handler, |
287 | IRQF_ONESHOT, name: "rtc" , data: info); |
288 | if (ret < 0) { |
289 | dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n" , |
290 | info->irq, ret); |
291 | goto out; |
292 | } |
293 | |
294 | info->rtc_dev->ops = &pm80x_rtc_ops; |
295 | info->rtc_dev->range_max = U32_MAX; |
296 | |
297 | ret = devm_rtc_register_device(info->rtc_dev); |
298 | if (ret) |
299 | goto out_rtc; |
300 | |
301 | /* |
302 | * enable internal XO instead of internal 3.25MHz clock since it can |
303 | * free running in PMIC power-down state. |
304 | */ |
305 | regmap_update_bits(map: info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO, |
306 | PM800_RTC1_USE_XO); |
307 | |
308 | /* remember whether this power up is caused by PMIC RTC or not */ |
309 | info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; |
310 | |
311 | device_init_wakeup(dev: &pdev->dev, enable: 1); |
312 | |
313 | return 0; |
314 | out_rtc: |
315 | pm80x_free_irq(pm80x: chip, irq: info->irq, data: info); |
316 | out: |
317 | return ret; |
318 | } |
319 | |
320 | static void pm80x_rtc_remove(struct platform_device *pdev) |
321 | { |
322 | struct pm80x_rtc_info *info = platform_get_drvdata(pdev); |
323 | pm80x_free_irq(pm80x: info->chip, irq: info->irq, data: info); |
324 | } |
325 | |
326 | static struct platform_driver pm80x_rtc_driver = { |
327 | .driver = { |
328 | .name = "88pm80x-rtc" , |
329 | .pm = &pm80x_rtc_pm_ops, |
330 | }, |
331 | .probe = pm80x_rtc_probe, |
332 | .remove_new = pm80x_rtc_remove, |
333 | }; |
334 | |
335 | module_platform_driver(pm80x_rtc_driver); |
336 | |
337 | MODULE_LICENSE("GPL" ); |
338 | MODULE_DESCRIPTION("Marvell 88PM80x RTC driver" ); |
339 | MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>" ); |
340 | MODULE_ALIAS("platform:88pm80x-rtc" ); |
341 | |