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, |
