diff options
Diffstat (limited to 'drivers/rtc/rtc-sirfsoc.c')
-rw-r--r-- | drivers/rtc/rtc-sirfsoc.c | 66 |
1 files changed, 51 insertions, 15 deletions
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index 76e38007ba90..d2ac6688e5c7 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c | |||
@@ -47,6 +47,7 @@ struct sirfsoc_rtc_drv { | |||
47 | unsigned irq_wake; | 47 | unsigned irq_wake; |
48 | /* Overflow for every 8 years extra time */ | 48 | /* Overflow for every 8 years extra time */ |
49 | u32 overflow_rtc; | 49 | u32 overflow_rtc; |
50 | spinlock_t lock; | ||
50 | #ifdef CONFIG_PM | 51 | #ifdef CONFIG_PM |
51 | u32 saved_counter; | 52 | u32 saved_counter; |
52 | u32 saved_overflow_rtc; | 53 | u32 saved_overflow_rtc; |
@@ -61,7 +62,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, | |||
61 | 62 | ||
62 | rtcdrv = dev_get_drvdata(dev); | 63 | rtcdrv = dev_get_drvdata(dev); |
63 | 64 | ||
64 | local_irq_disable(); | 65 | spin_lock_irq(&rtcdrv->lock); |
65 | 66 | ||
66 | rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); | 67 | rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); |
67 | 68 | ||
@@ -84,7 +85,8 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, | |||
84 | if (sirfsoc_rtc_iobrg_readl( | 85 | if (sirfsoc_rtc_iobrg_readl( |
85 | rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E) | 86 | rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E) |
86 | alrm->enabled = 1; | 87 | alrm->enabled = 1; |
87 | local_irq_enable(); | 88 | |
89 | spin_unlock_irq(&rtcdrv->lock); | ||
88 | 90 | ||
89 | return 0; | 91 | return 0; |
90 | } | 92 | } |
@@ -99,7 +101,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, | |||
99 | if (alrm->enabled) { | 101 | if (alrm->enabled) { |
100 | rtc_tm_to_time(&(alrm->time), &rtc_alarm); | 102 | rtc_tm_to_time(&(alrm->time), &rtc_alarm); |
101 | 103 | ||
102 | local_irq_disable(); | 104 | spin_lock_irq(&rtcdrv->lock); |
103 | 105 | ||
104 | rtc_status_reg = sirfsoc_rtc_iobrg_readl( | 106 | rtc_status_reg = sirfsoc_rtc_iobrg_readl( |
105 | rtcdrv->rtc_base + RTC_STATUS); | 107 | rtcdrv->rtc_base + RTC_STATUS); |
@@ -123,14 +125,15 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, | |||
123 | rtc_status_reg |= SIRFSOC_RTC_AL0E; | 125 | rtc_status_reg |= SIRFSOC_RTC_AL0E; |
124 | sirfsoc_rtc_iobrg_writel( | 126 | sirfsoc_rtc_iobrg_writel( |
125 | rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); | 127 | rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); |
126 | local_irq_enable(); | 128 | |
129 | spin_unlock_irq(&rtcdrv->lock); | ||
127 | } else { | 130 | } else { |
128 | /* | 131 | /* |
129 | * if this function was called with enabled=0 | 132 | * if this function was called with enabled=0 |
130 | * then it could mean that the application is | 133 | * then it could mean that the application is |
131 | * trying to cancel an ongoing alarm | 134 | * trying to cancel an ongoing alarm |
132 | */ | 135 | */ |
133 | local_irq_disable(); | 136 | spin_lock_irq(&rtcdrv->lock); |
134 | 137 | ||
135 | rtc_status_reg = sirfsoc_rtc_iobrg_readl( | 138 | rtc_status_reg = sirfsoc_rtc_iobrg_readl( |
136 | rtcdrv->rtc_base + RTC_STATUS); | 139 | rtcdrv->rtc_base + RTC_STATUS); |
@@ -146,7 +149,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, | |||
146 | rtcdrv->rtc_base + RTC_STATUS); | 149 | rtcdrv->rtc_base + RTC_STATUS); |
147 | } | 150 | } |
148 | 151 | ||
149 | local_irq_enable(); | 152 | spin_unlock_irq(&rtcdrv->lock); |
150 | } | 153 | } |
151 | 154 | ||
152 | return 0; | 155 | return 0; |
@@ -209,12 +212,38 @@ static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd, | |||
209 | } | 212 | } |
210 | } | 213 | } |
211 | 214 | ||
215 | static int sirfsoc_rtc_alarm_irq_enable(struct device *dev, | ||
216 | unsigned int enabled) | ||
217 | { | ||
218 | unsigned long rtc_status_reg = 0x0; | ||
219 | struct sirfsoc_rtc_drv *rtcdrv; | ||
220 | |||
221 | rtcdrv = dev_get_drvdata(dev); | ||
222 | |||
223 | spin_lock_irq(&rtcdrv->lock); | ||
224 | |||
225 | rtc_status_reg = sirfsoc_rtc_iobrg_readl( | ||
226 | rtcdrv->rtc_base + RTC_STATUS); | ||
227 | if (enabled) | ||
228 | rtc_status_reg |= SIRFSOC_RTC_AL0E; | ||
229 | else | ||
230 | rtc_status_reg &= ~SIRFSOC_RTC_AL0E; | ||
231 | |||
232 | sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); | ||
233 | |||
234 | spin_unlock_irq(&rtcdrv->lock); | ||
235 | |||
236 | return 0; | ||
237 | |||
238 | } | ||
239 | |||
212 | static const struct rtc_class_ops sirfsoc_rtc_ops = { | 240 | static const struct rtc_class_ops sirfsoc_rtc_ops = { |
213 | .read_time = sirfsoc_rtc_read_time, | 241 | .read_time = sirfsoc_rtc_read_time, |
214 | .set_time = sirfsoc_rtc_set_time, | 242 | .set_time = sirfsoc_rtc_set_time, |
215 | .read_alarm = sirfsoc_rtc_read_alarm, | 243 | .read_alarm = sirfsoc_rtc_read_alarm, |
216 | .set_alarm = sirfsoc_rtc_set_alarm, | 244 | .set_alarm = sirfsoc_rtc_set_alarm, |
217 | .ioctl = sirfsoc_rtc_ioctl | 245 | .ioctl = sirfsoc_rtc_ioctl, |
246 | .alarm_irq_enable = sirfsoc_rtc_alarm_irq_enable | ||
218 | }; | 247 | }; |
219 | 248 | ||
220 | static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) | 249 | static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) |
@@ -223,6 +252,8 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) | |||
223 | unsigned long rtc_status_reg = 0x0; | 252 | unsigned long rtc_status_reg = 0x0; |
224 | unsigned long events = 0x0; | 253 | unsigned long events = 0x0; |
225 | 254 | ||
255 | spin_lock(&rtcdrv->lock); | ||
256 | |||
226 | rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS); | 257 | rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS); |
227 | /* this bit will be set ONLY if an alarm was active | 258 | /* this bit will be set ONLY if an alarm was active |
228 | * and it expired NOW | 259 | * and it expired NOW |
@@ -240,6 +271,9 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) | |||
240 | rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); | 271 | rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); |
241 | } | 272 | } |
242 | sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); | 273 | sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); |
274 | |||
275 | spin_unlock(&rtcdrv->lock); | ||
276 | |||
243 | /* this should wake up any apps polling/waiting on the read | 277 | /* this should wake up any apps polling/waiting on the read |
244 | * after setting the alarm | 278 | * after setting the alarm |
245 | */ | 279 | */ |
@@ -267,6 +301,8 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) | |||
267 | if (rtcdrv == NULL) | 301 | if (rtcdrv == NULL) |
268 | return -ENOMEM; | 302 | return -ENOMEM; |
269 | 303 | ||
304 | spin_lock_init(&rtcdrv->lock); | ||
305 | |||
270 | err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base); | 306 | err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base); |
271 | if (err) { | 307 | if (err) { |
272 | dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n"); | 308 | dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n"); |
@@ -286,14 +322,6 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) | |||
286 | rtc_div = ((32768 / RTC_HZ) / 2) - 1; | 322 | rtc_div = ((32768 / RTC_HZ) / 2) - 1; |
287 | sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); | 323 | sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); |
288 | 324 | ||
289 | rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, | ||
290 | &sirfsoc_rtc_ops, THIS_MODULE); | ||
291 | if (IS_ERR(rtcdrv->rtc)) { | ||
292 | err = PTR_ERR(rtcdrv->rtc); | ||
293 | dev_err(&pdev->dev, "can't register RTC device\n"); | ||
294 | return err; | ||
295 | } | ||
296 | |||
297 | /* 0x3 -> RTC_CLK */ | 325 | /* 0x3 -> RTC_CLK */ |
298 | sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, | 326 | sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, |
299 | rtcdrv->rtc_base + RTC_CLOCK_SWITCH); | 327 | rtcdrv->rtc_base + RTC_CLOCK_SWITCH); |
@@ -308,6 +336,14 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) | |||
308 | rtcdrv->overflow_rtc = | 336 | rtcdrv->overflow_rtc = |
309 | sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); | 337 | sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); |
310 | 338 | ||
339 | rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, | ||
340 | &sirfsoc_rtc_ops, THIS_MODULE); | ||
341 | if (IS_ERR(rtcdrv->rtc)) { | ||
342 | err = PTR_ERR(rtcdrv->rtc); | ||
343 | dev_err(&pdev->dev, "can't register RTC device\n"); | ||
344 | return err; | ||
345 | } | ||
346 | |||
311 | rtcdrv->irq = platform_get_irq(pdev, 0); | 347 | rtcdrv->irq = platform_get_irq(pdev, 0); |
312 | err = devm_request_irq( | 348 | err = devm_request_irq( |
313 | &pdev->dev, | 349 | &pdev->dev, |