diff options
Diffstat (limited to 'drivers/rtc/rtc-vr41xx.c')
| -rw-r--r-- | drivers/rtc/rtc-vr41xx.c | 65 |
1 files changed, 34 insertions, 31 deletions
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index be9c70d0b193..884b635f028b 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Driver for NEC VR4100 series Real Time Clock unit. | 2 | * Driver for NEC VR4100 series Real Time Clock unit. |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2003-2006 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> | 4 | * Copyright (C) 2003-2008 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> |
| 5 | * | 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
| 7 | * it under the terms of the GNU General Public License as published by | 7 | * it under the terms of the GNU General Public License as published by |
| @@ -34,7 +34,7 @@ | |||
| 34 | 34 | ||
| 35 | MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); | 35 | MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); |
| 36 | MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); | 36 | MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); |
| 37 | MODULE_LICENSE("GPL"); | 37 | MODULE_LICENSE("GPL v2"); |
| 38 | 38 | ||
| 39 | /* RTC 1 registers */ | 39 | /* RTC 1 registers */ |
| 40 | #define ETIMELREG 0x00 | 40 | #define ETIMELREG 0x00 |
| @@ -82,7 +82,6 @@ static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ | |||
| 82 | 82 | ||
| 83 | static DEFINE_SPINLOCK(rtc_lock); | 83 | static DEFINE_SPINLOCK(rtc_lock); |
| 84 | static char rtc_name[] = "RTC"; | 84 | static char rtc_name[] = "RTC"; |
| 85 | static unsigned long periodic_frequency; | ||
| 86 | static unsigned long periodic_count; | 85 | static unsigned long periodic_count; |
| 87 | static unsigned int alarm_enabled; | 86 | static unsigned int alarm_enabled; |
| 88 | static int aie_irq = -1; | 87 | static int aie_irq = -1; |
| @@ -207,10 +206,37 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) | |||
| 207 | return 0; | 206 | return 0; |
| 208 | } | 207 | } |
| 209 | 208 | ||
| 210 | static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | 209 | static int vr41xx_rtc_irq_set_freq(struct device *dev, int freq) |
| 211 | { | 210 | { |
| 212 | unsigned long count; | 211 | unsigned long count; |
| 213 | 212 | ||
| 213 | count = RTC_FREQUENCY; | ||
| 214 | do_div(count, freq); | ||
| 215 | |||
| 216 | periodic_count = count; | ||
| 217 | |||
| 218 | spin_lock_irq(&rtc_lock); | ||
| 219 | |||
| 220 | rtc1_write(RTCL1LREG, count); | ||
| 221 | rtc1_write(RTCL1HREG, count >> 16); | ||
| 222 | |||
| 223 | spin_unlock_irq(&rtc_lock); | ||
| 224 | |||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | static int vr41xx_rtc_irq_set_state(struct device *dev, int enabled) | ||
| 229 | { | ||
| 230 | if (enabled) | ||
| 231 | enable_irq(pie_irq); | ||
| 232 | else | ||
| 233 | disable_irq(pie_irq); | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) | ||
| 239 | { | ||
| 214 | switch (cmd) { | 240 | switch (cmd) { |
| 215 | case RTC_AIE_ON: | 241 | case RTC_AIE_ON: |
| 216 | spin_lock_irq(&rtc_lock); | 242 | spin_lock_irq(&rtc_lock); |
| @@ -232,33 +258,6 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long | |||
| 232 | 258 | ||
| 233 | spin_unlock_irq(&rtc_lock); | 259 | spin_unlock_irq(&rtc_lock); |
| 234 | break; | 260 | break; |
| 235 | case RTC_PIE_ON: | ||
| 236 | enable_irq(pie_irq); | ||
| 237 | break; | ||
| 238 | case RTC_PIE_OFF: | ||
| 239 | disable_irq(pie_irq); | ||
| 240 | break; | ||
| 241 | case RTC_IRQP_READ: | ||
| 242 | return put_user(periodic_frequency, (unsigned long __user *)arg); | ||
| 243 | break; | ||
| 244 | case RTC_IRQP_SET: | ||
| 245 | if (arg > MAX_PERIODIC_RATE) | ||
| 246 | return -EINVAL; | ||
| 247 | |||
| 248 | periodic_frequency = arg; | ||
| 249 | |||
| 250 | count = RTC_FREQUENCY; | ||
| 251 | do_div(count, arg); | ||
| 252 | |||
| 253 | periodic_count = count; | ||
| 254 | |||
| 255 | spin_lock_irq(&rtc_lock); | ||
| 256 | |||
| 257 | rtc1_write(RTCL1LREG, count); | ||
| 258 | rtc1_write(RTCL1HREG, count >> 16); | ||
| 259 | |||
| 260 | spin_unlock_irq(&rtc_lock); | ||
| 261 | break; | ||
| 262 | case RTC_EPOCH_READ: | 261 | case RTC_EPOCH_READ: |
| 263 | return put_user(epoch, (unsigned long __user *)arg); | 262 | return put_user(epoch, (unsigned long __user *)arg); |
| 264 | case RTC_EPOCH_SET: | 263 | case RTC_EPOCH_SET: |
| @@ -309,6 +308,8 @@ static const struct rtc_class_ops vr41xx_rtc_ops = { | |||
| 309 | .set_time = vr41xx_rtc_set_time, | 308 | .set_time = vr41xx_rtc_set_time, |
| 310 | .read_alarm = vr41xx_rtc_read_alarm, | 309 | .read_alarm = vr41xx_rtc_read_alarm, |
| 311 | .set_alarm = vr41xx_rtc_set_alarm, | 310 | .set_alarm = vr41xx_rtc_set_alarm, |
| 311 | .irq_set_freq = vr41xx_rtc_irq_set_freq, | ||
| 312 | .irq_set_state = vr41xx_rtc_irq_set_state, | ||
| 312 | }; | 313 | }; |
| 313 | 314 | ||
| 314 | static int __devinit rtc_probe(struct platform_device *pdev) | 315 | static int __devinit rtc_probe(struct platform_device *pdev) |
| @@ -346,6 +347,8 @@ static int __devinit rtc_probe(struct platform_device *pdev) | |||
| 346 | goto err_iounmap_all; | 347 | goto err_iounmap_all; |
| 347 | } | 348 | } |
| 348 | 349 | ||
| 350 | rtc->max_user_freq = MAX_PERIODIC_RATE; | ||
| 351 | |||
| 349 | spin_lock_irq(&rtc_lock); | 352 | spin_lock_irq(&rtc_lock); |
| 350 | 353 | ||
| 351 | rtc1_write(ECMPLREG, 0); | 354 | rtc1_write(ECMPLREG, 0); |
