Blame view
drivers/rtc/rtc-sirfsoc.c
11.6 KB
e88b815e0
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/* * SiRFSoC Real Time Clock interface for Linux * * Copyright (c) 2013 Cambridge Silicon Radio Limited, a CSR plc group company. * * Licensed under GPLv2 or later. */ #include <linux/module.h> #include <linux/err.h> #include <linux/rtc.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/of.h> |
dfe6c04aa
|
16 |
#include <linux/regmap.h> |
e88b815e0
|
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <linux/rtc/sirfsoc_rtciobrg.h> #define RTC_CN 0x00 #define RTC_ALARM0 0x04 #define RTC_ALARM1 0x18 #define RTC_STATUS 0x08 #define RTC_SW_VALUE 0x40 #define SIRFSOC_RTC_AL1E (1<<6) #define SIRFSOC_RTC_AL1 (1<<4) #define SIRFSOC_RTC_HZE (1<<3) #define SIRFSOC_RTC_AL0E (1<<2) #define SIRFSOC_RTC_HZ (1<<1) #define SIRFSOC_RTC_AL0 (1<<0) #define RTC_DIV 0x0c #define RTC_DEEP_CTRL 0x14 #define RTC_CLOCK_SWITCH 0x1c #define SIRFSOC_RTC_CLK 0x03 /* others are reserved */ /* Refer to RTC DIV switch */ #define RTC_HZ 16 /* This macro is also defined in arch/arm/plat-sirfsoc/cpu.c */ #define RTC_SHIFT 4 #define INTR_SYSRTC_CN 0x48 struct sirfsoc_rtc_drv { struct rtc_device *rtc; u32 rtc_base; u32 irq; |
28984c7d9
|
48 |
unsigned irq_wake; |
e88b815e0
|
49 50 |
/* Overflow for every 8 years extra time */ u32 overflow_rtc; |
e9bc7363d
|
51 |
spinlock_t lock; |
dfe6c04aa
|
52 |
struct regmap *regmap; |
e88b815e0
|
53 54 55 56 57 |
#ifdef CONFIG_PM u32 saved_counter; u32 saved_overflow_rtc; #endif }; |
dfe6c04aa
|
58 59 60 61 62 63 64 65 66 67 68 69 70 |
static u32 sirfsoc_rtc_readl(struct sirfsoc_rtc_drv *rtcdrv, u32 offset) { u32 val; regmap_read(rtcdrv->regmap, rtcdrv->rtc_base + offset, &val); return val; } static void sirfsoc_rtc_writel(struct sirfsoc_rtc_drv *rtcdrv, u32 offset, u32 val) { regmap_write(rtcdrv->regmap, rtcdrv->rtc_base + offset, val); } |
e88b815e0
|
71 72 73 74 75 |
static int sirfsoc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { unsigned long rtc_alarm, rtc_count; struct sirfsoc_rtc_drv *rtcdrv; |
b7efdf3b1
|
76 |
rtcdrv = dev_get_drvdata(dev); |
e88b815e0
|
77 |
|
e9bc7363d
|
78 |
spin_lock_irq(&rtcdrv->lock); |
e88b815e0
|
79 |
|
dfe6c04aa
|
80 |
rtc_count = sirfsoc_rtc_readl(rtcdrv, RTC_CN); |
e88b815e0
|
81 |
|
dfe6c04aa
|
82 |
rtc_alarm = sirfsoc_rtc_readl(rtcdrv, RTC_ALARM0); |
e88b815e0
|
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
memset(alrm, 0, sizeof(struct rtc_wkalrm)); /* * assume alarm interval not beyond one round counter overflow_rtc: * 0->0xffffffff */ /* if alarm is in next overflow cycle */ if (rtc_count > rtc_alarm) rtc_time_to_tm((rtcdrv->overflow_rtc + 1) << (BITS_PER_LONG - RTC_SHIFT) | rtc_alarm >> RTC_SHIFT, &(alrm->time)); else rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | rtc_alarm >> RTC_SHIFT, &(alrm->time)); |
dfe6c04aa
|
98 |
if (sirfsoc_rtc_readl(rtcdrv, RTC_STATUS) & SIRFSOC_RTC_AL0E) |
e88b815e0
|
99 |
alrm->enabled = 1; |
e9bc7363d
|
100 101 |
spin_unlock_irq(&rtcdrv->lock); |
e88b815e0
|
102 103 104 105 106 107 108 109 110 |
return 0; } static int sirfsoc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { unsigned long rtc_status_reg, rtc_alarm; struct sirfsoc_rtc_drv *rtcdrv; |
b7efdf3b1
|
111 |
rtcdrv = dev_get_drvdata(dev); |
e88b815e0
|
112 113 114 |
if (alrm->enabled) { rtc_tm_to_time(&(alrm->time), &rtc_alarm); |
e9bc7363d
|
115 |
spin_lock_irq(&rtcdrv->lock); |
e88b815e0
|
116 |
|
dfe6c04aa
|
117 |
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); |
e88b815e0
|
118 119 120 121 122 123 124 125 |
if (rtc_status_reg & SIRFSOC_RTC_AL0E) { /* * An ongoing alarm in progress - ingore it and not * to return EBUSY */ dev_info(dev, "An old alarm was set, will be replaced by a new one "); } |
dfe6c04aa
|
126 |
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, rtc_alarm << RTC_SHIFT); |
e88b815e0
|
127 128 129 130 131 132 133 134 |
rtc_status_reg &= ~0x07; /* mask out the lower status bits */ /* * This bit RTC_AL sets it as a wake-up source for Sleep Mode * Writing 1 into this bit will clear it */ rtc_status_reg |= SIRFSOC_RTC_AL0; /* enable the RTC alarm interrupt */ rtc_status_reg |= SIRFSOC_RTC_AL0E; |
dfe6c04aa
|
135 |
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); |
e9bc7363d
|
136 137 |
spin_unlock_irq(&rtcdrv->lock); |
e88b815e0
|
138 139 140 141 142 143 |
} else { /* * if this function was called with enabled=0 * then it could mean that the application is * trying to cancel an ongoing alarm */ |
e9bc7363d
|
144 |
spin_lock_irq(&rtcdrv->lock); |
e88b815e0
|
145 |
|
dfe6c04aa
|
146 |
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); |
e88b815e0
|
147 148 149 150 151 152 153 |
if (rtc_status_reg & SIRFSOC_RTC_AL0E) { /* clear the RTC status register's alarm bit */ rtc_status_reg &= ~0x07; /* write 1 into SIRFSOC_RTC_AL0 to force a clear */ rtc_status_reg |= (SIRFSOC_RTC_AL0); /* Clear the Alarm enable bit */ rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); |
dfe6c04aa
|
154 155 |
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); |
e88b815e0
|
156 |
} |
e9bc7363d
|
157 |
spin_unlock_irq(&rtcdrv->lock); |
e88b815e0
|
158 159 160 161 162 163 164 165 166 167 |
} return 0; } static int sirfsoc_rtc_read_time(struct device *dev, struct rtc_time *tm) { unsigned long tmp_rtc = 0; struct sirfsoc_rtc_drv *rtcdrv; |
b7efdf3b1
|
168 |
rtcdrv = dev_get_drvdata(dev); |
e88b815e0
|
169 170 171 172 173 174 |
/* * This patch is taken from WinCE - Need to validate this for * correctness. To work around sirfsoc RTC counter double sync logic * fail, read several times to make sure get stable value. */ do { |
dfe6c04aa
|
175 |
tmp_rtc = sirfsoc_rtc_readl(rtcdrv, RTC_CN); |
e88b815e0
|
176 |
cpu_relax(); |
dfe6c04aa
|
177 |
} while (tmp_rtc != sirfsoc_rtc_readl(rtcdrv, RTC_CN)); |
e88b815e0
|
178 179 180 181 182 183 184 185 186 187 188 |
rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | tmp_rtc >> RTC_SHIFT, tm); return 0; } static int sirfsoc_rtc_set_time(struct device *dev, struct rtc_time *tm) { unsigned long rtc_time; struct sirfsoc_rtc_drv *rtcdrv; |
b7efdf3b1
|
189 |
rtcdrv = dev_get_drvdata(dev); |
e88b815e0
|
190 191 192 193 |
rtc_tm_to_time(tm, &rtc_time); rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT); |
dfe6c04aa
|
194 195 |
sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); sirfsoc_rtc_writel(rtcdrv, RTC_CN, rtc_time << RTC_SHIFT); |
e88b815e0
|
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
return 0; } static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { switch (cmd) { case RTC_PIE_ON: case RTC_PIE_OFF: case RTC_UIE_ON: case RTC_UIE_OFF: case RTC_AIE_ON: case RTC_AIE_OFF: return 0; default: return -ENOIOCTLCMD; } } |
09e427f87
|
216 217 218 219 220 221 222 |
static int sirfsoc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { unsigned long rtc_status_reg = 0x0; struct sirfsoc_rtc_drv *rtcdrv; rtcdrv = dev_get_drvdata(dev); |
e9bc7363d
|
223 |
spin_lock_irq(&rtcdrv->lock); |
09e427f87
|
224 |
|
dfe6c04aa
|
225 |
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); |
09e427f87
|
226 227 228 229 |
if (enabled) rtc_status_reg |= SIRFSOC_RTC_AL0E; else rtc_status_reg &= ~SIRFSOC_RTC_AL0E; |
dfe6c04aa
|
230 |
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); |
e9bc7363d
|
231 232 |
spin_unlock_irq(&rtcdrv->lock); |
09e427f87
|
233 234 235 236 |
return 0; } |
e88b815e0
|
237 238 239 240 241 |
static const struct rtc_class_ops sirfsoc_rtc_ops = { .read_time = sirfsoc_rtc_read_time, .set_time = sirfsoc_rtc_set_time, .read_alarm = sirfsoc_rtc_read_alarm, .set_alarm = sirfsoc_rtc_set_alarm, |
09e427f87
|
242 243 |
.ioctl = sirfsoc_rtc_ioctl, .alarm_irq_enable = sirfsoc_rtc_alarm_irq_enable |
e88b815e0
|
244 245 246 247 248 249 250 |
}; static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) { struct sirfsoc_rtc_drv *rtcdrv = pdata; unsigned long rtc_status_reg = 0x0; unsigned long events = 0x0; |
e9bc7363d
|
251 |
spin_lock(&rtcdrv->lock); |
dfe6c04aa
|
252 |
rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); |
e88b815e0
|
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
/* this bit will be set ONLY if an alarm was active * and it expired NOW * So this is being used as an ASSERT */ if (rtc_status_reg & SIRFSOC_RTC_AL0) { /* * clear the RTC status register's alarm bit * mask out the lower status bits */ rtc_status_reg &= ~0x07; /* write 1 into SIRFSOC_RTC_AL0 to ACK the alarm interrupt */ rtc_status_reg |= (SIRFSOC_RTC_AL0); /* Clear the Alarm enable bit */ rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); } |
dfe6c04aa
|
268 269 |
sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); |
e9bc7363d
|
270 271 |
spin_unlock(&rtcdrv->lock); |
e88b815e0
|
272 273 274 275 276 277 278 279 280 281 282 283 284 |
/* this should wake up any apps polling/waiting on the read * after setting the alarm */ events |= RTC_IRQF | RTC_AF; rtc_update_irq(rtcdrv->rtc, 1, events); return IRQ_HANDLED; } static const struct of_device_id sirfsoc_rtc_of_match[] = { { .compatible = "sirf,prima2-sysrtc"}, {}, }; |
dfe6c04aa
|
285 286 287 288 289 290 |
const struct regmap_config sysrtc_regmap_config = { .reg_bits = 32, .val_bits = 32, .fast_io = true, }; |
e88b815e0
|
291 292 293 294 295 296 297 298 299 300 301 |
MODULE_DEVICE_TABLE(of, sirfsoc_rtc_of_match); static int sirfsoc_rtc_probe(struct platform_device *pdev) { int err; unsigned long rtc_div; struct sirfsoc_rtc_drv *rtcdrv; struct device_node *np = pdev->dev.of_node; rtcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_rtc_drv), GFP_KERNEL); |
98e2d21fa
|
302 |
if (rtcdrv == NULL) |
e88b815e0
|
303 |
return -ENOMEM; |
e88b815e0
|
304 |
|
e9bc7363d
|
305 |
spin_lock_init(&rtcdrv->lock); |
e88b815e0
|
306 307 308 309 |
err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base); if (err) { dev_err(&pdev->dev, "unable to find base address of rtc node in dtb "); |
3d09162e9
|
310 |
return err; |
e88b815e0
|
311 312 313 314 315 316 |
} platform_set_drvdata(pdev, rtcdrv); /* Register rtc alarm as a wakeup source */ device_init_wakeup(&pdev->dev, 1); |
dfe6c04aa
|
317 318 319 320 321 322 323 324 325 |
rtcdrv->regmap = devm_regmap_init_iobg(&pdev->dev, &sysrtc_regmap_config); if (IS_ERR(rtcdrv->regmap)) { err = PTR_ERR(rtcdrv->regmap); dev_err(&pdev->dev, "Failed to allocate register map: %d ", err); return err; } |
e88b815e0
|
326 327 328 329 330 331 |
/* * Set SYS_RTC counter in RTC_HZ HZ Units * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 * If 16HZ, therefore RTC_DIV = 1023; */ rtc_div = ((32768 / RTC_HZ) / 2) - 1; |
dfe6c04aa
|
332 |
sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); |
e88b815e0
|
333 |
|
e88b815e0
|
334 |
/* 0x3 -> RTC_CLK */ |
dfe6c04aa
|
335 |
sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); |
e88b815e0
|
336 337 |
/* reset SYS RTC ALARM0 */ |
dfe6c04aa
|
338 |
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); |
e88b815e0
|
339 340 |
/* reset SYS RTC ALARM1 */ |
dfe6c04aa
|
341 |
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); |
e88b815e0
|
342 343 344 |
/* Restore RTC Overflow From Register After Command Reboot */ rtcdrv->overflow_rtc = |
dfe6c04aa
|
345 |
sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); |
e88b815e0
|
346 |
|
0e9532552
|
347 348 349 350 351 352 353 354 |
rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sirfsoc_rtc_ops, THIS_MODULE); if (IS_ERR(rtcdrv->rtc)) { err = PTR_ERR(rtcdrv->rtc); dev_err(&pdev->dev, "can't register RTC device "); return err; } |
e88b815e0
|
355 356 357 358 359 360 361 362 363 364 365 |
rtcdrv->irq = platform_get_irq(pdev, 0); err = devm_request_irq( &pdev->dev, rtcdrv->irq, sirfsoc_rtc_irq_handler, IRQF_SHARED, pdev->name, rtcdrv); if (err) { dev_err(&pdev->dev, "Unable to register for the SiRF SOC RTC IRQ "); |
3d09162e9
|
366 |
return err; |
e88b815e0
|
367 368 369 |
} return 0; |
e88b815e0
|
370 371 372 373 |
} static int sirfsoc_rtc_remove(struct platform_device *pdev) { |
e88b815e0
|
374 |
device_init_wakeup(&pdev->dev, 0); |
e88b815e0
|
375 376 377 |
return 0; } |
3916b09ee
|
378 |
#ifdef CONFIG_PM_SLEEP |
e88b815e0
|
379 380 |
static int sirfsoc_rtc_suspend(struct device *dev) { |
3916b09ee
|
381 |
struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); |
e88b815e0
|
382 |
rtcdrv->overflow_rtc = |
dfe6c04aa
|
383 |
sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); |
e88b815e0
|
384 385 |
rtcdrv->saved_counter = |
dfe6c04aa
|
386 |
sirfsoc_rtc_readl(rtcdrv, RTC_CN); |
e88b815e0
|
387 |
rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; |
3916b09ee
|
388 |
if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq)) |
28984c7d9
|
389 |
rtcdrv->irq_wake = 1; |
e88b815e0
|
390 391 392 |
return 0; } |
3916b09ee
|
393 |
static int sirfsoc_rtc_resume(struct device *dev) |
e88b815e0
|
394 395 |
{ u32 tmp; |
3916b09ee
|
396 |
struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); |
e88b815e0
|
397 398 |
/* |
3916b09ee
|
399 |
* if resume from snapshot and the rtc power is lost, |
e88b815e0
|
400 401 |
* restroe the rtc settings */ |
dfe6c04aa
|
402 |
if (SIRFSOC_RTC_CLK != sirfsoc_rtc_readl(rtcdrv, RTC_CLOCK_SWITCH)) { |
e88b815e0
|
403 404 |
u32 rtc_div; /* 0x3 -> RTC_CLK */ |
dfe6c04aa
|
405 |
sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); |
e88b815e0
|
406 407 408 409 410 411 |
/* * Set SYS_RTC counter in RTC_HZ HZ Units * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 * If 16HZ, therefore RTC_DIV = 1023; */ rtc_div = ((32768 / RTC_HZ) / 2) - 1; |
dfe6c04aa
|
412 |
sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); |
e88b815e0
|
413 414 |
/* reset SYS RTC ALARM0 */ |
dfe6c04aa
|
415 |
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); |
e88b815e0
|
416 417 |
/* reset SYS RTC ALARM1 */ |
dfe6c04aa
|
418 |
sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); |
e88b815e0
|
419 420 421 422 423 424 425 |
} rtcdrv->overflow_rtc = rtcdrv->saved_overflow_rtc; /* * if current counter is small than previous, * it means overflow in sleep */ |
dfe6c04aa
|
426 |
tmp = sirfsoc_rtc_readl(rtcdrv, RTC_CN); |
e88b815e0
|
427 428 429 430 431 432 |
if (tmp <= rtcdrv->saved_counter) rtcdrv->overflow_rtc++; /* *PWRC Value Be Changed When Suspend, Restore Overflow * In Memory To Register */ |
dfe6c04aa
|
433 |
sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); |
e88b815e0
|
434 |
|
3916b09ee
|
435 |
if (device_may_wakeup(dev) && rtcdrv->irq_wake) { |
e88b815e0
|
436 |
disable_irq_wake(rtcdrv->irq); |
28984c7d9
|
437 438 |
rtcdrv->irq_wake = 0; } |
e88b815e0
|
439 440 441 |
return 0; } |
e88b815e0
|
442 |
#endif |
3916b09ee
|
443 444 |
static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops, sirfsoc_rtc_suspend, sirfsoc_rtc_resume); |
e88b815e0
|
445 446 447 448 |
static struct platform_driver sirfsoc_rtc_driver = { .driver = { .name = "sirfsoc-rtc", |
e88b815e0
|
449 |
.pm = &sirfsoc_rtc_pm_ops, |
d149632e0
|
450 |
.of_match_table = sirfsoc_rtc_of_match, |
e88b815e0
|
451 452 453 454 455 456 457 458 459 460 |
}, .probe = sirfsoc_rtc_probe, .remove = sirfsoc_rtc_remove, }; module_platform_driver(sirfsoc_rtc_driver); MODULE_DESCRIPTION("SiRF SoC rtc driver"); MODULE_AUTHOR("Xianglong Du <Xianglong.Du@csr.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:sirfsoc-rtc"); |